#install.packages("knitr")
<<<<<<< .merge_file_a05344
Warning message:
Unknown or uninitialised column: `Country`.
=======
Warning message:
In load(file = path, envir = e) :
strings not representable in native encoding will be translated to UTF-8
>>>>>>> .merge_file_a10112
#install.packages("grid")
#install.packages("MLRMPA")
#install.packages("dprep")
#install.packages("normalr")
#install.packages("ggcorrplot")
#install.packages("RColorBrewer")
#install.packages("rgdal")
#install.packages("jsonlite")
#install.packages("RColorBrewer")
#install.packages("readr")
Sys.setlocale("LC_ALL", "English")
[1] "LC_COLLATE=English_United States.1252;LC_CTYPE=English_United States.1252;LC_MONETARY=English_United States.1252;LC_NUMERIC=C;LC_TIME=English_United States.1252"
Sys.setenv("LANGUAGE"="En")
library(gridExtra)
library(dplyr)
library(lubridate)
library(magrittr)
library(ggplot2)
library(tidyr)
library(knitr)
library(normalr)
library(ggcorrplot)
library(leaflet)
library(plotly)
library(RColorBrewer)
library(readr)
#??src_mysql
my_db <- src_mysql(
dbname = "covid19",
host = "cvd-database.cmxpnyylhkiw.us-east-2.rds.amazonaws.com",
user = "admin",
password = "RprojectCovid19"
)
<<<<<<< .merge_file_a05344
`src_mysql()` is deprecated as of dplyr 1.0.0.
Please use `tbl()` directly with a database connection
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.
=======
`src_mysql()` was deprecated in dplyr 1.0.0.
Please use `tbl()` directly with a database connection
>>>>>>> .merge_file_a10112
my_db
src: mysql 8.0.21 [admin@cvd-database.cmxpnyylhkiw.us-east-2.rds.amazonaws.com:/covid19]
tbls: covid19_confirmed, covid19_confirmed_global, covid19_deaths, covid19_deaths_global,
covid19_recovered, covid19_recovered_global, covid19_thailand, covidus, data_ethnic, data_gender,
data_health, data_lockdown, data_population, data_testing, gdp19, healthranking, population,
pornhub, sars_2003, us_gdp, us_homeless, us_latlong, world_temp
##import data
df_conf <- tbl(my_db, sql("select * from covid19_confirmed"))
df_conf <- as.data.frame(df_conf)
df_conf
df_deaths <- tbl(my_db, sql("select * from covid19_deaths"))
df_deaths <- as.data.frame(df_deaths)
df_deaths
df_recover <- tbl(my_db, sql("select * from covid19_recovered"))
df_recover <- as.data.frame(df_recover)
df_recover
##check the time frame of the data
n.col <- ncol(df_conf)
dates <- names(df_conf)[5:n.col]%>% mdy()
range(dates)
[1] "2020-01-22" "2021-01-22"
min.date <- min(dates)
max.date <- max(dates)
min.date.txt <- min.date %>% format('%d %b %Y')
max.date.txt <- max.date %>% format('%d %b %Y')
#clean data
cleanData <- function(data) {
## remove some columns
data %<>% select(-c(Province.State, Lat, Long)) %>% rename(country=Country.Region)
## convert from wide to long format
data %<>% gather(key=date, value=count, -country)
## convert from character to date
data %<>% mutate(date = date %>% mdy())
## aggregate by country
data %<>% group_by(country, date) %>% summarise(count=sum(count, na.rm=T)) %>% as.data.frame()
return(data)
}
## clean the three data sets
data.confirmed <- df_conf %>% cleanData() %>% rename(confirmed=count)
`summarise()` regrouping output by 'country' (override with `.groups` argument)
data.deaths <- df_deaths %>% cleanData() %>% rename(deaths=count)
`summarise()` regrouping output by 'country' (override with `.groups` argument)
data.recovered <- df_recover %>% cleanData() %>% rename(recovered=count)
`summarise()` regrouping output by 'country' (override with `.groups` argument)
data <- data.confirmed %>% merge(data.deaths, all=T) %>% merge(data.recovered, all=T)
data
## countries/regions with confirmed cases, excl. cruise ships
countries <- data %>% pull(country) %>% setdiff('Cruise Ship')
data
data.world <- data %>% group_by(date) %>%
summarise(country='World',
confirmed = sum(confirmed, na.rm=T),
deaths = sum(deaths, na.rm=T),
recovered = sum(recovered, na.rm=T))
`summarise()` ungrouping output (override with `.groups` argument)
data %<>% rbind(data.world)
data
data %<>% mutate(current.confirmed = confirmed - deaths - recovered)
#View(data)
# World confirmed cases map
world.location <- df_conf
#View(world.location )
world.location$confirmed <- world.location [, ncol(world.location )]
world.location %<>% select(c(Country.Region, Province.State, Lat, Long, confirmed)) %>%
mutate(txt=paste0(Country.Region, ' - ', Province.State, ': ', confirmed))
map.confirmed <- leaflet(width=1200, height=800) %>% addTiles()
# circle marker (units in pixels)
map.confirmed %<>% addCircleMarkers(world.location$Long, world.location$Lat,
# radius=2+log2(x$confirmed),
radius=0.02*sqrt(world.location$confirmed),
stroke=F,
color='red', fillOpacity=0.3,
label=world.location$txt)
# world
map.confirmed
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
## China
map.confirmed %>% setView(95, 35, zoom=4)
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
## Australia and New Zealand
map.confirmed %>% setView(135, -27, zoom=4)
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
## US and Canada
map.confirmed %>% setView(-105, 40, zoom=4)
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
## Europe
map.confirmed %>% setView(10, 50, zoom=4)
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
# new.confirmed new.deaths new.recovered
data %<>% arrange(country, date)
n <- nrow(data)
day1 <- min(data$date)
data %<>% mutate(new.confirmed = ifelse(date == day1, NA, confirmed - lag(confirmed, n=1)),
new.deaths = ifelse(date == day1, NA, deaths - lag(deaths, n=1)),
new.recovered = ifelse(date == day1, NA, recovered - lag(recovered, n=1)))
data %<>% mutate(new.confirmed = ifelse(new.confirmed < 0, 0, new.confirmed),
new.deaths = ifelse(new.deaths < 0, 0, new.deaths),
new.recovered = ifelse(new.recovered < 0, 0, new.recovered))
## death rate based on total deaths and recovered cases
data %<>% mutate(rate.upper = (100 * deaths / (deaths + recovered)) %>% round(1),
rate.upper = ifelse(is.nan(rate.upper), 0, rate.upper))
## lower bound: death rate based on total confirmed cases
data %<>% mutate(rate.lower = (100 * deaths / confirmed) %>% round(1),
rate.lower = ifelse(is.nan(rate.lower), 0, rate.lower))
## death rate based on the number of death/recovered on every single day
data %<>% mutate(rate.daily = (100 * new.deaths / (new.deaths + new.recovered)) %>% round(1),
rate.daily = ifelse(is.nan(rate.daily), 0, rate.daily))
#View(data)
## convert from wide to long format
data.long <- data %>%
select(c(country, date, confirmed, current.confirmed, recovered, deaths)) %>%
gather(key=type, value=count, -c(country, date))
## set factor levels to show them in a desirable order
data.long %<>% mutate(type=recode_factor(type, confirmed='Total Confirmed',
current.confirmed='Current Confirmed',
recovered='Recovered',
deaths='Deaths'))
#View(data.long)
##Number of case World
world <- filter(data.long,country == 'World')
world
plot_world.area <- world %>% filter(type != 'Total Confirmed') %>%
ggplot(aes(x=date, y=count)) +
geom_area(aes(fill=type), alpha=0.5) +
labs(title=paste0('Numbers of Cases Worldwide - ', max.date.txt)) +
scale_fill_manual(values=c('red', 'green', 'black')) +
theme(legend.title=element_blank(), legend.position='bottom',
plot.title = element_text(size=7),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
legend.key.size=unit(0.2, 'cm'),
legend.text=element_text(size=6),
axis.text=element_text(size=7),
axis.text.x=element_text(angle=45, hjust=1))
plot_world.line <- world %>%
ggplot(aes(x=date, y=count,color = type)) +
geom_line(aes(color=type)) +
labs(title=paste0('Numbers of Cases Worldwide (log scale) - ', max.date.txt)) +
#scale_color_manual(values=c('blue', 'red', 'green', 'black')) +
theme(legend.title=element_blank(), legend.position='bottom',
plot.title = element_text(size=7),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
legend.key.size=unit(0.2, 'cm'),
legend.text=element_text(size=6),
axis.text=element_text(size=7),
axis.text.x=element_text(angle=45, hjust=1)) +
scale_y_continuous(trans='log10')
## show two plots side by side
grid.arrange(plot_world.area, plot_world.line, ncol=2)

gly.plot_world.area <- ggplotly(plot_world.area)
gly.plot_world.area
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
gly.plot_world.line <- ggplotly(plot_world.line)
gly.plot_world.line
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
data.world.all <- data %>% filter(country == "World")
## a scatter plot with a smoothed line and vertical x-axis labels
plot_acc.deaths <- ggplot(data.world.all, aes(x=date, y=deaths)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Accumulative Deaths') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot_recovered <- ggplot(data.world.all, aes(x=date, y=recovered)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Accumulative Recovered Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot_new.deaths <- ggplot(data.world.all, aes(x=date, y=new.deaths)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='New Deaths') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot_new.recovered <- ggplot(data.world.all, aes(x=date, y=new.recovered)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='New Recovered Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
## show four plots together, with 2 plots in each row
grid.arrange(plot_acc.deaths, plot_recovered, plot_new.deaths, plot_new.recovered, nrow=2)

## convert from wide to long format, for drawing area plots
rates.long <- data %>%
select(c(country, date, rate.upper, rate.lower, rate.daily)) %>%
gather(key=type, value=count, -c(country, date))
# set factor levels to show them in a desirable order
rates.long %<>% mutate(type=recode_factor(type, rate.daily='Daily',
rate.upper='Upper bound',
rate.lower = 'Lower bound'))
#View(rates.long)
plot_rates <- rates.long %>% filter(country == "World") %>%
ggplot(aes(x = date, y = count, color = type)) +
geom_line() +
labs(title = "World Death Rate (%)") +
xlab("") + ylab("Death Rate (%)")
plot_rates

gly.rates <- ggplotly(plot_rates)
gly.rates
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
## ranking by confirmed cases
data.latest.all <- data %>% filter(date == max(date)) %>%
select(country, date,confirmed, new.confirmed, current.confirmed,
recovered, deaths, new.deaths, death.rate=rate.lower) %>%
mutate(ranking = dense_rank(desc(confirmed))) %>%
arrange(ranking)
#View(data.latest.all)
k <- 20
## top 20 countries: 21 incl. 'World'
top.countries <- data.latest.all %>% filter(ranking <= k + 1) %>%
arrange(ranking) %>% pull(country) %>% as.character()
top.countries %>% setdiff('World') %>% print()
[1] "US" "India" "Brazil" "Russia" "United Kingdom"
[6] "France" "Spain" "Italy" "Turkey" "Germany"
[11] "Colombia" "Argentina" "Mexico" "Poland" "South Africa"
[16] "Iran" "Ukraine" "Peru" "Indonesia" "Netherlands"
df <- data.long %>% filter(country %in% top.countries) %>%
mutate(country=country %>% factor(levels=c(top.countries))) %>%
filter(country != 'World' & type != 'Total Confirmed') %>%
ggplot(aes(x=date, y=count, color=type)) +
geom_line()+
#geom_area(alpha=0.5) +
# xlab('') + ylab('') +
labs(title=paste0('Numbers of COVID-19 Cases in Top 20 Countries - ',
max.date.txt)) +
scale_color_manual(values=c('red', 'green', 'black')) +
theme(legend.title=element_blank(), legend.position='bottom',
plot.title = element_text(size=12),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
legend.key.size=unit(0.4, 'cm'),
legend.text=element_text(size=12),
strip.text.x=element_text(size=12),
axis.text=element_text(size=12),
axis.text.x=element_text(angle=45, hjust=1)) +
facet_wrap(~country, ncol=4, scales='free_y') +
scale_y_continuous(trans='log10')
df

data.latest <- data.latest.all %>% filter(!is.na(country)) %>%
mutate(country=ifelse(ranking <= k + 1, as.character(country), 'Others')) %>%
mutate(country=country %>% factor(levels=c(top.countries, 'Others')))
data.latest %<>% group_by(country) %>%
summarise(confirmed=sum(confirmed), new.confirmed=sum(new.confirmed),
current.confirmed=sum(current.confirmed),
recovered=sum(recovered), deaths=sum(deaths), new.deaths=sum(new.deaths)) %>%
mutate(death.rate=(100 * deaths/confirmed) %>% round(1))
`summarise()` ungrouping output (override with `.groups` argument)
data.latest
data.latest %<>% select(c(country, confirmed, deaths, death.rate,
new.confirmed, new.deaths, current.confirmed,recovered)) %>%
mutate(recover.rate=(100 * recovered/confirmed) %>% round(1))
data.latest
mostconfirm <- data.latest %>% select(c(country,confirmed)) %>% filter(country=="World")
mostrecover <- data.latest %>% select(c(country,recovered)) %>% filter(country=="World")
mostdeath <- data.latest %>% select(c(country,deaths)) %>% filter(country=="World")
df_pop <- tbl(my_db, sql("select * from population "))
df_pop <- as.data.frame(df_pop)
df_pop <- rename(df_pop,"country"="Country")
# Add World Population
world_pop <- sum(df_pop$`Population (2020)`)
df_pop[nrow(df_pop) + 1,] = c("World", world_pop)
# Add Other Countries Population
top_pop <- filter(df_pop, df_pop$country %in% top.countries & df_pop$country != "World")
top_pop <- sum(top_pop$`Population (2020)` %>% as.numeric())
others_pop <- (world_pop - top_pop)
df_pop[nrow(df_pop) + 1,] = c("Others", others_pop)
#View(df_pop)
data.latest <- merge(x = data.latest, y = df_pop, by = "country", all.x = TRUE)
data.latest
data.latest <- rename(data.latest,"population" = "Population (2020)")
data.latest$population <- data.latest$population %>% as.numeric()
data.latest <- data.latest %>%
select(c(country, confirmed, deaths, death.rate,
new.confirmed, new.deaths,
current.confirmed, recovered, recover.rate, population)) %>%
mutate(confirm.rate = (100 * confirmed / population) %>% round(1))
data.latest
## % of death
data.latest %>% mutate(death.rate=death.rate %>% format(nsmall=1) %>% paste0('%'))
## convert from wide to long format, for drawing area plots
data.latest.long <- data.latest %>% filter(country!='World') %>%
gather(key=type, value=count, -country)
## set factor levels to show them with proper text and in a desirable order
data.latest.long %<>% mutate(type=recode_factor(type,
confirmed='Total Confirmed',
deaths='Total Deaths',
death.rate='Death Rate (%)',
new.confirmed='New Confirmed (compared with one day before)',
new.deaths='New Deaths (compared with one day before)',
current.confirmed='Current Confirmed',
recover.rate = 'Recovered Rate(%)',
confirm.rate = 'Confirmed Rate(%)'))
#View(data.latest.long)
data.one.dem <- filter(data.latest.long,type=='Total Confirmed'
| type=='Total Deaths'
| type=='Current Confirmed')
data.two.dem <- filter(data.latest.long,type=='Death Rate (%)'
# | type=='New Confirmed (compared with one day before)'
# | type=='New Deaths (compared with one day before)'
| type=='Recovered Rate(%)'
| type=='Confirmed Rate(%)')
data.two.dem
## bar chart
data.one.dem %>% ggplot(aes(x=country, y=count, fill=country, group=country)) +
geom_bar(stat='identity') +
geom_text(aes(label=count, y=count), size=3, vjust=0) +
xlab('') + ylab('') +
labs(title=paste0('Top 20 Countries with Most Confirmed Cases - ', max.date.txt)) +
scale_fill_discrete(name='Country', labels=aes(count)) +
theme(legend.title=element_blank(),
legend.position='none',
plot.title=element_text(size=13),
axis.text=element_text(size=8),
axis.text.x=element_text(angle=45, hjust=1)) +
facet_wrap(~type, ncol=1, scales='free_y')

data.two.dem$facet <- factor(data.two.dem$type, levels = c('Confirmed Rate(%)', 'Recovered Rate(%)','Death Rate (%)'))
data.two.dem %>%
ggplot(aes(x=country, y=count, fill=country, group=country)) +
geom_bar(stat='identity') +
geom_text(aes(label=count, y=count), size=4, vjust=0) +
xlab('') + ylab('') +
labs(title=paste0('Top 20 Countries with Most Confirmed Cases - ', max.date.txt)) +
scale_fill_discrete(name='Country', labels=aes(count)) +
theme(legend.title=element_blank(),
legend.position='none',
plot.title=element_text(size=13),
axis.text=element_text(size=10),
axis.text.x=element_text(size=10,angle=45, hjust=1)) +
facet_wrap(~facet, ncol=1, scales='free_y')

##GDP
df_gdp2019 <- tbl(my_db, sql("select * from gdp19"))
df_gdp2019 <- as.data.frame(df_gdp2019)
df_gdp2019
#healthranking data
df_healt <- tbl(my_db, sql("select * from healthranking"))
df_healt <- as.data.frame(df_healt)
df_healt <- select(df_healt,c("country","healthCareIndex"))
#View(df_healt)
#Top20Pornhub data
#df_pornhub <- tbl(my_db, sql("select * from Pornhub"))
#df_pornhub <- as.data.frame(df_pornhub)
#df_pornhub
# temp data
df_temp <- tbl(my_db, sql("select * from world_temp"))
df_temp <- as.data.frame(df_temp)
df_temp$Country[df_temp$Country == "United States"] <- "US"
df_city <- select(df_temp,c("Country","City")) %>%
rename(country=Country) %>%
rename(city=City)
numofcity <- aggregate(city ~ country, data = df_city, length)
#clean data
df_temp <- select(df_temp,c("Country","Avg_Year")) %>%
rename(country=Country)
#View(df_temp)
#df_temp <- data.frame(country=df_temp[,1],avg=rowMeans(df_temp[,-1]))
df_temp <- df_temp %<>% group_by(country) %>% summarise(avg_temp = mean(Avg_Year,na.rm = TRUE)%>% round(1))
`summarise()` ungrouping output (override with `.groups` argument)
df_temp
##temp bar
df_temp.all <- df_temp %>% merge(data.latest.all)
#View(df_temp.all)
df_temp_top.all <- df_temp.all %>% filter(country %in% top.countries) %>%
mutate(ranking = ranking - 1) %>%
arrange(ranking)
#View(df_temp_top.all)
g_temp_top <- df_temp_top.all %>%
ggplot(aes(x = reorder(country, ranking), y = avg_temp, fill = avg_temp)) +
labs(title=paste0("Temperature in Top 20 countries"), subtitle = "Average Temperature in Top 20 countries with most confirmed cases (°C) (2020)") +
scale_color_gradient(low = "#93DBFF", high = "#FF7771") +
geom_text(aes(label=avg_temp, y=avg_temp), size=4, vjust=-0.5) +
geom_bar(stat = "identity", position = "dodge") +
theme(
legend.title=element_blank(),
legend.position='none',
plot.title=element_text(size = 15, hjust = 0.5),
plot.subtitle = element_text(size = 12, hjust = 0.5),
axis.text=element_text(size=8),
axis.text.x=element_text(size = 9, angle=45, hjust=1)) +
scale_x_discrete(name = "Country") +
scale_y_discrete(name = "Average Temperature")
#labs(title = "Temperature in Top 20 countries", subtitle = "Temperature in Top 20 countries with most confirmed cases (°C)")
#g_temp_top
g_temp_top

#data.latest.all
lat.long <- rename(df_conf, "country" = "Country.Region", "city" = "Province.State") %>%
select("country", "Lat", "Long") %>%
merge(df_temp.all[c("country","confirmed", "recovered", "deaths", "avg_temp", "ranking")], by = "country") %>%
distinct(country, .keep_all = TRUE) %>%
mutate(ranking = ranking - 1) %>%
arrange(ranking)
#View(lat.long)
label_world <- lat.long
label_world$avg_temp <- as.numeric(label_world[, names(label_world) %in% c("avg_temp")])
label_world <- label_world %>%
mutate(txt=paste0('<b>',ranking, '</b>',
'<br/>','<b>',country, '</b>',
'<br/>', "Temperature: ",avg_temp, ' °C',
'<br/>', "Confirmed: ", confirmed,
'<br/>', "Deaths: ", deaths,
'<br/>', "Recovered: ", recovered
))
label_world$txt <- label_world$txt %>% lapply(htmltools::HTML)
label_world
label_top <- label_world %>% filter(ranking < 21)
label_top
# Temperature Map
wpal <- colorNumeric("YlOrRd", label_world$avg_temp, n = 4)
topIcon <- makeIcon("star.png",
#iconUrl = "https://static.vecteezy.com/system/resources/previews/001/189/063/non_2x/star-rounded-png.png",
iconWidth = 10, iconHeight = 10
#iconAnchorX = 20, iconAnchorY = 20
)
label_world <- label_world %>% filter(ranking > 20)
m <- leaflet(width=1200, height=800) %>% addTiles()
m %<>% addCircleMarkers(label_world$Long, label_world$Lat,
# radius=2+log2(x$confirmed),
radius=10,#*log2(m.world$avg.temp),
stroke=F,
#color='red',
color = wpal(label_world$avg_temp),
fillOpacity=0.5,
#popup=label.top$txt
label= label_world$txt,
group = "World"
) %>%
addCircleMarkers(label_top$Long, label_top$Lat,
# radius=2+log2(x$confirmed),
radius=10,#*log2(m.world$avg.temp),
stroke=F,
#color='red',
color = wpal(label_top$avg_temp),
fillOpacity=0.5,
#popup=label.top$txt
label= label_top$txt,
group = "Top 20 Countries"
) %>%
addLabelOnlyMarkers(label_top$Long, label_top$Lat, label = label_top$ranking,
labelOptions = labelOptions(noHide = TRUE, textOnly = TRUE,
direction = "head",
offset = c(5,4)),
group = "Top 20 Countries") %>%
addLegend("bottomright", pal = wpal, values = label_world$avg_temp, opacity = 1,
labFormat = labelFormat(suffix = " °C"),
title = "Temperature") %>%
addLayersControl(
#baseGroups = c("OSM (default)", "Toner", "Toner Lite"),
overlayGroups = c("Top 20 Countries", "World"),
options = layersControlOptions(collapsed = FALSE)
)
m
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
gdp.top20 <- df_gdp2019 %>%
select(c("rank", "country", "GDP (millions of US dollars)")) %>%
merge(data.latest.all %>%
select(country, ranking, confirmed, recovered, deaths) %>%
filter(country %in% top.countries & country != "World"), by = "country") %>%
arrange(ranking) %>%
mutate(ranking = ranking - 1)
gdp.top20 %<>% rename("GDP" = "GDP (millions of US dollars)")
gdp.top20
g <- ggplot(gdp.top20, aes(x = GDP, y = reorder(country, -ranking))) +
geom_histogram(stat = "identity", aes(fill = GDP))+
scale_fill_gradient("GDP", low = "#FF4038", high = "#50E952") +
labs(title=paste0("GDP of Top 20 Countries in 2019 (millions of US dollars)")) +
geom_text(aes(label=GDP, x = GDP), size=3.5, hjust=-0.2) +
xlab("GDP (millions of US dollars)") +
ylab("") +
theme(legend.title=element_blank())
Ignoring unknown parameters: binwidth, bins, pad
g

gly.top.gdp <- ggplotly(g)
gly.top.gdp
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
# Pornhub
df_pornhub <- tbl(my_db, sql("select * from pornhub"))
df_pornhub <- as.data.frame(df_pornhub)
df_pornhub
# Sars
df_sars <- tbl(my_db, sql("select * from sars_2003"))
df_sars <- as.data.frame(df_sars)
#View(df_sars)
dates.s <- df_sars[,1]%>% mdy()
range(dates.s)
[1] "2003-03-17" "2003-07-11"
min.date.s <- min(dates.s)
max.date.s <- max(dates.s)
min.date.txt.s <- min.date.s %>% format('%d %b %Y')
max.date.txt.s <- max.date.s %>% format('%d %b %Y')
day1.sars <- min.date.s
# clean data Sars
data.sars <- df_sars %>% rename(c("date" = "Date", "confirmed" = "Cumulative_number" ,"deaths" = "Number_deaths", "recovered" = "Number_recovered")) %>%
mutate(date = date %>% mdy()) %>%
group_by(country, date) %>% as.data.frame()
# Add World's Sars cases
world.sars <- data.sars %>% group_by(date) %>%
summarise(country='World',
confirmed = sum(confirmed, na.rm=T),
deaths = sum(deaths, na.rm=T),
recovered = sum(recovered, na.rm=T))
`summarise()` ungrouping output (override with `.groups` argument)
data.sars %<>% rbind(world.sars)
data.sars %<>% mutate(current.confirmed = confirmed - deaths - recovered)
#View(world.sars)
data.sars
#rate
data.sars %<>% arrange(country, date)
n <- nrow(data.sars)
day1.sars <- min(data.sars$date)
data.sars %<>% mutate(new.confirmed = ifelse(date == day1.sars, NA, confirmed - lag(confirmed, n=1)),
new.deaths = ifelse(date == day1.sars, NA, deaths - lag(deaths, n=1)),
new.recovered = ifelse(date == day1.sars, NA, recovered - lag(recovered, n=1)))
data.sars %<>% mutate(new.confirmed = ifelse(new.confirmed < 0, 0, new.confirmed),
new.deaths = ifelse(new.deaths < 0, 0, new.deaths),
new.recovered = ifelse(new.recovered < 0, 0, new.recovered))
## death rate based on total deaths and recovered cases
data.sars %<>% mutate(rate.upper = (100 * deaths / (deaths + recovered)) %>% round(1),
rate.upper = ifelse(is.nan(rate.upper), 0, rate.upper))
## lower bound: death rate based on total confirmed cases
data.sars %<>% mutate(rate.lower = (100 * deaths / confirmed) %>% round(1),
rate.lower = ifelse(is.nan(rate.lower), 0, rate.lower))
## death rate based on the number of death/recovered on every single day
data.sars %<>% mutate(rate.daily = (100 * new.deaths / (new.deaths + new.recovered)) %>% round(1),
rate.daily = ifelse(is.nan(rate.daily), 0, rate.daily))
#View(data.sars)
## convert from wide to long format
data.sars.long <- data.sars %>%
select(c(country, date, confirmed, current.confirmed, recovered, deaths)) %>%
gather(key=type, value=count, -c(country, date))
## set factor levels to show them in a desirable order
data.sars.long %<>% mutate(type=recode_factor(type, confirmed='Total Confirmed',
current.confirmed='Current Confirmed',
recovered='Recovered',
deaths='Deaths'))
#View(data.sars.long)
# World sars' long data
world.sars.long <- data.sars.long %>%
filter(country == "World")
#View(world.sars.long)
g <- ggplot(world.sars.long, aes(date, count, color = type)) +
geom_line()+
labs(title = "Number of Cases Worldwide: SARs")+
xlab("")+
ylab("")
g

gly.g <- ggplotly(g)
gly.g
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
gly.plot_world.line
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
df_sars_lastdate <- data.sars %>%
filter(date == max.date.s)
df_sars_lastdate
## Current Confirmed Cases
data.sars.world <- data.sars %>% filter(country=='World')
#View(data.sars.world)
n <- nrow(data.sars.world)
#View(data.sars.world)
plot_sars.currconf <- ggplot(data.sars.world, aes(x=date, y=current.confirmed)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Current Confirmed Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot_sars.newconf <- ggplot(data.sars.world, aes(x=date, y=new.confirmed)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Daily New Confirmed Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
## show two plots side by side
grid.arrange(plot_sars.currconf, plot_sars.newconf, ncol=2)

## a scatter plot with a smoothed line and vertical x-axis labels
plot_sars.accdeaths <- ggplot(data.sars.world, aes(x=date, y=deaths)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Accumulative Deaths') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot_sars.accrecov <- ggplot(data.sars.world, aes(x=date, y=recovered)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Accumulative Recovered Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot_sars.newdeaths <- ggplot(data.sars.world, aes(x=date, y=new.deaths)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='New Deaths') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot_sars.newrecov <- ggplot(data.sars.world, aes(x=date, y=new.recovered)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='New Recovered Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
## show four plots together, with 2 plots in each row
grid.arrange(plot_sars.accdeaths, plot_sars.accrecov, plot_sars.newdeaths, plot_sars.newrecov, nrow=2)

#Top 20 with gdp
data.longGDP <- df_gdp2019 %>% gather(key=year, value=GDP, -c(country))
data.top <- data.latest %>% filter(!country %in% c('World', 'Others'))
data.top <- head(data.top,20)
#View(data.latest)
data.gdp <- filter(data.longGDP,year=='2020')
df_sars_lastdate_confirmed <- df_sars_lastdate %>%
select("country", "confirmed") %>%
rename(sars = "confirmed")
#View(df_sars_lastdate_confirmed)
#merge
mergcountry = function(data1,data2){
data <- merge(x = data1, y = data2, by = "country", all.x = TRUE)
return(data)
}
data.top.world <- merge(x = data.top, y = df_gdp2019, by = "country", all.x = TRUE) %>%
select(-c(code,rank,new.confirmed,new.deaths,current.confirmed,population)) %>%
rename(GDP="GDP (millions of US dollars)")
data.top.world <- merge(x = data.top.world, y = df_healt, by = "country", all.x = TRUE) %>%
rename(healthcare="healthCareIndex")
#data.top.world <- mergcountry(data.top.world, df_temp)
data.top.world <- merge(x = data.top.world, y = df_pornhub, by = "country", all.x = TRUE) %>%
rename(Pornhub = "PornhubIndex(%)")
data.top.world <- merge(x = data.top.world, y = df_sars_lastdate_confirmed, by = "country", all.x = TRUE)
data.top.world <- mergcountry(data.top.world, df_temp)
index <- is.na(data.top.world)
data.top.world[index] <- 0
data.top.world
View(data.top.world)
normalize = function(data){
#return ((data - min(data,na.rm = TRUE))/(max(data,na.rm = TRUE) - min(data,na.rm = TRUE)))
z <- scale(data);
tanh(z/2)
}
norm_data = as.data.frame(apply(data.top.world[,2:13],2,normalize))
corr_data <- norm_data
norm_data$country <- c("Argentina","Bangladesh","Brazil","Chile","Colombia","France","Germany","India","Iran","Italy","Mexico","Pakistan","Peru","Russia","saudi Arabia","South Africa","Spain","Turkey","United Kingdom","US")
norm_data <- norm_data[,c(ncol(norm_data),1:(ncol(norm_data)-1))]
rownames(norm_data) <- norm_data[,1]
norm_data[,1] <- NULL
#heatmap(as.matrix(norm_data[, -1]),scale="column",col= colorRampPalette(brewer.pal(8, "Blues"))(25))
#legend(x="bottomright", legend=c("-1", "0", "1"),
# fill=colorRampPalette(brewer.pal(8, "Blues"))(3))
# install.packages("gplots")
library("gplots")
library("stringr")
norm_data_plot <- select(norm_data,"confirm.rate","death.rate","recover.rate","healthcare","Pornhub","GDP","avg_temp", "sars")
norm_data_plot
world_clust <- as.matrix(norm_data_plot)
heatmap.clust <- heatmap.2(as.matrix(norm_data_plot),
scale="none",
col = colorRampPalette(c("#6D9EC1","white","#E46726"))(n = 200),
margins=c(10,6),trace="column")

#gly.heatmap2 <- plotly_build(heatmap.clust)
norm_data2 = as.data.frame(apply(data.top.world[,2:13],2,normalize))
norm_data2$country <- c("Argentina","Bangladesh","Brazil","Chile","Colombia","France","Germany","India","Iran","Italy","Mexico","Pakistan","Peru","Russia","saudi Arabia","South Africa","Spain","Turkey","United Kingdom","US")
#View(norm_data2)
norm_data_plot2 <- select(norm_data2,"country","confirm.rate","death.rate","recover.rate","healthcare","Pornhub","GDP","avg_temp", "sars")
#View(norm_data_plot2)
norm_data_plot2 %<>% gather(key=type, value=count, -c(country))
level_order <- factor(norm_data_plot2$type,
level =c("sars","Pornhub","GDP","avg_temp","healthcare","recover.rate","death.rate","confirm.rate"))
View(level_order)
ggplot(data = norm_data_plot2, aes(x=country, y=level_order, fill=count)) +
geom_tile() +
scale_fill_gradient(low = "pink", high = "blue") +
xlab("") +
ylab("") +
theme_bw() +
theme(axis.text.x = element_text(angle = 90,vjust = 1))+
theme(
axis.line = element_blank(),
axis.ticks = element_blank(),
panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
panel.border = element_blank(),
panel.background = element_blank(),
#legend.position = "none"
)

#correlation
corr_data %<>% select(c(GDP,confirm.rate,death.rate,recover.rate,healthcare,avg_temp,Pornhub, sars))
head(corr_data)
cor(corr_data)
GDP confirm.rate death.rate recover.rate healthcare avg_temp Pornhub
GDP 1.00000000 0.4342894 -0.23113988 -0.3937431 0.25183938 -0.05173909 0.71560225
confirm.rate 0.43428937 1.0000000 -0.34422360 -0.7182585 0.48153104 -0.36431596 0.43162144
death.rate -0.23113988 -0.3442236 1.00000000 0.1733012 -0.17258588 0.34643395 -0.04353792
recover.rate -0.39374308 -0.7182585 0.17330123 1.0000000 -0.76240251 0.26074521 -0.40887125
healthcare 0.25183938 0.4815310 -0.17258588 -0.7624025 1.00000000 -0.06716339 0.37579971
avg_temp -0.05173909 -0.3643160 0.34643395 0.2607452 -0.06716339 1.00000000 -0.11100774
Pornhub 0.71560225 0.4316214 -0.04353792 -0.4088713 0.37579971 -0.11100774 1.00000000
sars 0.97481805 0.4506609 -0.21325881 -0.3582828 0.16579089 -0.05509975 0.68006901
sars
GDP 0.97481805
confirm.rate 0.45066089
death.rate -0.21325881
recover.rate -0.35828282
healthcare 0.16579089
avg_temp -0.05509975
Pornhub 0.68006901
sars 1.00000000
plotcorr <- ggcorrplot(cor(corr_data),hc.order = TRUE,
outline.color = "white",
colors = c("#6D9EC1","white","#E46726"),
lab = TRUE)
plotcorr

## Data in US
df_us <- tbl(my_db, sql("select * from covidus"))
df_us <- as.data.frame(df_us)
df_us <- select(df_us, date, state, cases, deaths)
df_us_pop <- tbl(my_db, sql("select * from data_population"))
df_us_pop <- as.data.frame(df_us_pop)
df_us_gender <- tbl(my_db, sql("select * from data_gender"))
df_us_gender <- as.data.frame(df_us_gender)
df_us_ethnic <- tbl(my_db, sql("select * from data_ethnic"))
df_us_ethnic <- as.data.frame(df_us_ethnic)
df_us_lockdown <- tbl(my_db, sql("select * from data_lockdown"))
df_us_lockdown <- as.data.frame(df_us_lockdown)
df_us_health <- tbl(my_db, sql("select * from data_health"))
df_us_health <- as.data.frame(df_us_health)
df_us_testing <- tbl(my_db, sql("select * from data_testing"))
df_us_testing <- as.data.frame(df_us_testing)
df_us <- df_us %>%
mutate(date = date %>% mdy()) %>%
rename("confirmed" = "cases")
#data.us
dates.us <- df_us[,1]
range(dates.us)
[1] "2020-01-21" "2020-12-24"
min.date.us <- min(dates.us)
max.date.us <- max(dates.us)
min.date.txt.us <- min.date.us %>% format('%d %b %Y')
max.date.txt.us <- max.date.us %>% format('%d %b %Y')
day1.us <- min(df_us$date)
data.us.total <- df_us %>% group_by(date) %>%
summarise(state='US',
confirmed = sum(confirmed, na.rm=T),
deaths = sum(deaths, na.rm=T))
`summarise()` ungrouping output (override with `.groups` argument)
#View(data.us.total)
data.us <- df_us
data.us %<>% rbind(data.us.total)
View(data.us)
data.us.long <- data.us %>%
gather(key = type, value = count, -c(date, state))
View(data.us.long)
us.total <- data.us.total %>%
mutate(new.confirmed = ifelse(date == day1, 0, confirmed - lag(confirmed, n=1)),
new.deaths = ifelse(date == day1, 0, deaths - lag(deaths, n=1)))
us.total %<>% mutate(new.confirmed = ifelse(new.confirmed < 0, 0, new.confirmed),
new.deaths = ifelse(new.deaths < 0, 0, new.deaths))
us.total
most_us <- us.total %>% filter(date == max.date.us)
us.total.long <- us.total %>%
gather(key = type, value = count, -c(date, state))
#View(us.total.long)
plot_us.cases <- data.us.long %>% filter(state == "US") %>%
ggplot(aes(x = date, y = count)) +
geom_area(aes(fill=type), alpha=0.5) +
# labs(title = paste0("Cumulative cases in US : ", min.date.txt.us, '-', max.date.txt.us, " (Stack, Log Scale)")) +
scale_y_continuous(trans='log10') +
scale_fill_manual(values=c('red', 'black'))+
ylab("") +
theme(axis.title = element_text(size=8))
#View(us.total.long )
plot_us.newconf <- us.total.long %>%
filter(type %in% c("new.confirmed","new.deaths")) %>%
ggplot(aes(x = date, y = count, color = type)) +
geom_line() +
#labs(title = paste0("Daily confirmed cases in US : ", min.date.txt.us, '-', max.date.txt.us)) +
xlab("Date") +
ylab("Confirmed cases")
gly.plot_us.cases <- ggplotly(plot_us.cases)
Transformation introduced infinite values in continuous y-axis
gly.plot_us.cases <- gly.plot_us.cases %>%
layout(title = paste0("<b>Cumulative cases in US : ", min.date.txt.us, '-', max.date.txt.us, " (Stack, Log Scale)"),
font=list(size = 10))
gly.plot_us.newconf <- ggplotly(plot_us.newconf) %>%
layout(title = paste0("<b>Daily confirmed cases in US : ", min.date.txt.us, '-', max.date.txt.us),
font=list(size = 10))
gly.plot_us.cases
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
gly.plot_us.newconf
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
NA
data.us %<>% mutate(new.confirmed = ifelse(date == day1, NA, confirmed - lag(confirmed, n=1)),
new.deaths = ifelse(date == day1, NA, deaths - lag(deaths, n=1)))
data.us %<>% mutate(new.confirmed = ifelse(new.confirmed < 0, 0, new.confirmed),
new.deaths = ifelse(new.deaths < 0, 0, new.deaths))
View(data.us)
#data.us.daily <- data.us %>% filter(state == "US")
#View(data.us.daily)
data.us.pop <- df_us_pop %>% select(State, Population) %>%
rename("state" = "State")
#data.us.pop
data.us.gender <- df_us_gender %>% select(State, Male, Female) %>%
rename("state" = "State")
data.us.gender
data.us.latest <- data.us %>%
filter(date == max.date.us) %>%
merge(data.us.pop, by = "state", all.x = T) %>%
merge(data.us.gender, by = "state", all.x = T)
#View(data.us.latest)
data.us.latest$Population[data.us.latest$state == "US"] <- sum(data.us.pop$Population)
data.us.latest %<>% mutate(ranking = dense_rank(desc(confirmed)),
confirmed.rate = (100 * confirmed / Population) %>% round(2),
death.rate = (100 * deaths / confirmed) %>% round(2),
Male.confirmed = (Male * confirmed) %>% round(0),
Female.confirmed = Female * confirmed %>% round(0),
Male.deaths = Male * deaths,
Female.deaths = Female * deaths) %>%
arrange(ranking)
top.us <- data.us.latest[,1]
top.us
[1] "US" "California" "Texas"
[4] "Florida" "Illinois" "New York"
[7] "Ohio" "Georgia" "Pennsylvania"
[10] "Tennessee" "Michigan" "Wisconsin"
[13] "North Carolina" "Indiana" "Arizona"
[16] "New Jersey" "Minnesota" "Missouri"
[19] "Massachusetts" "Alabama" "Virginia"
[22] "Colorado" "Louisiana" "South Carolina"
[25] "Iowa" "Oklahoma" "Maryland"
[28] "Utah" "Kentucky" "Washington"
[31] "Kansas" "Nevada" "Arkansas"
[34] "Mississippi" "Connecticut" "Nebraska"
[37] "Idaho" "New Mexico" "Oregon"
[40] "Puerto Rico" "South Dakota" "North Dakota"
[43] "Rhode Island" "Montana" "West Virginia"
[46] "Delaware" "Alaska" "Wyoming"
[49] "New Hampshire" "District of Columbia" "Maine"
[52] "Hawaii" "Guam" "Vermont"
[55] "Virgin Islands" "Northern Mariana Islands"
#View(top.us)
data.us.latest.show <- data.us.latest %>% select(state,date,confirmed,deaths, confirmed.rate, death.rate)
#View(data.us.latest.show)
# List of top 20 state
k <- 20
data.us.top <- data.us.latest %>%
filter(ranking <= k+1) %>%
arrange(ranking)
#View(data.us.top)
us.state.top <- data.us.top %>% pull(state) %>% as.character()
us.state.top %>% setdiff('US') %>% print()
[1] "California" "Texas" "Florida" "Illinois" "New York"
[6] "Ohio" "Georgia" "Pennsylvania" "Tennessee" "Michigan"
[11] "Wisconsin" "North Carolina" "Indiana" "Arizona" "New Jersey"
[16] "Minnesota" "Missouri" "Massachusetts" "Alabama" "Virginia"
# confirmed rate & death rate of top 20 state
g.rate <- data.us.latest %>% filter(state %in% us.state.top & state != "US") %>%
select(state, confirmed.rate, death.rate, ranking) %>%
gather(key = Type, value = Percent, -c(state, ranking)) %>%
ggplot(aes(x=reorder(state, -desc(ranking)), y=Percent, fill = Percent)) +
geom_bar(stat='identity') +
scale_fill_gradient(low = "#ebbc62", high = "#b42006") +
geom_text(aes(label=Percent, y=Percent), size=3, vjust=0) +
xlab('') + ylab('') +
labs(title=paste0('Confirmed Rate & Death Rate of Top 20 State in US')) +
#scale_fill_continuous(name='State', labels=aes(Percent)) +
theme(legend.title=element_blank(),
legend.position='none',
plot.title=element_text(size=13),
axis.text=element_text(size=8),
axis.text.x=element_text(angle=45, hjust=1)) +
facet_wrap(~Type, ncol=1, scales='free_y')
g.rate

us.confirmed.num <- data.us.top$confirmed[data.us.top$state == "US"] %>% as.numeric()
us.confirmed.num
[1] 18706036
data.us.top %<>% mutate(confirmed.per.us = (confirmed * 100 / us.confirmed.num) %>% round(1))
data.us.top
g.us.top1 <- data.us.top %>%
filter(state != "US") %>%
select(state, confirmed, confirmed.per.us, ranking) %>%
gather(key = Type, value = count, -c(state, ranking, confirmed.per.us)) %>%
arrange(ranking) %>%
ggplot(aes(x = reorder(state, ranking), y = count, fill = count)) +
geom_bar(stat = "identity") +
#labs(title = "20 state in US with most confirmed cases") +
scale_color_gradient(low = "#93DBFF", high = "#FF7771") +
xlab("") +
ylab("Confirmed Cases") +
geom_text(aes(label=paste0(confirmed.per.us, "%")), size=3, vjust=-0.5) +
theme(axis.text.x = element_text(angle = 90,vjust = 0.5))+
theme(
axis.line = element_blank(),
axis.ticks = element_blank(),
panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
panel.border = element_blank(),
panel.background = element_blank(),
#legend.position = "none"
)
g.us.top1

gly.us.top1 <- ggplotly(g.us.top1)
gly.us.top1
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
data.us.latest.corr <- df_us %>%filter(date==max.date.us)
#View(data.us.latest.corr)
data.us.latest.corr %<>% mutate(ranking = dense_rank(desc(confirmed))) %>% arrange(ranking)
top.us <- data.us.latest.corr[,2]
#top.us
# List of top 20 state
k <- 19
data.us.latest.top <- data.us.latest.corr %>%
filter(ranking <= k+1) %>%
arrange(ranking)
#View(data.us.latest.top)
us.state.top <- data.us.latest.top %>% pull(state) %>% as.character()
us.state.top %>% setdiff('US') %>% print()
[1] "California" "Texas" "Florida" "Illinois" "New York"
[6] "Ohio" "Georgia" "Pennsylvania" "Tennessee" "Michigan"
[11] "Wisconsin" "North Carolina" "Indiana" "Arizona" "New Jersey"
[16] "Minnesota" "Missouri" "Massachusetts" "Alabama" "Virginia"
#View(us.state.top)
#gender in us
df_us_gender <- tbl(my_db, sql("select * from data_gender"))
df_us_gender <- as.data.frame(df_us_gender)
df_us_gender <- select(df_us_gender,c("State","Male","Female"))
df_us_gender <- rename(df_us_gender,"state"="State")
df_us_gender
#population in us
df_us_pop <- tbl(my_db, sql("select * from data_population"))
df_us_pop <- as.data.frame(df_us_pop)
df_us_pop <- select(df_us_pop,c("State","Population"))
df_us_pop <- rename(df_us_pop,"state"="State")
df_us_pop
#lockdown in us
df_us_lockdown <- tbl(my_db, sql("select * from data_lockdown"))
df_us_lockdown <- as.data.frame(df_us_lockdown)
df_us_lockdown <- select(df_us_lockdown,c("State","Day lockdown"))
df_us_lockdown <- rename(df_us_lockdown,"state"="State")
df_us_lockdown
#GDP in us
df_us_gdp <- tbl(my_db, sql("select * from us_gdp"))
df_us_gdp <- as.data.frame(df_us_gdp )
df_us_gdp <- select(df_us_gdp ,c("State","GDPs"))
df_us_gdp <- rename(df_us_gdp ,"state"="State")
df_us_gdp
#homeless in us
df_us_homeless <- tbl(my_db, sql("select * from us_homeless"))
df_us_homeless <- as.data.frame(df_us_homeless)
df_us_homeless <- select(df_us_homeless,c("State","Homeless"))
df_us_homeless <- rename(df_us_homeless,"state"="State")
df_us_homeless
#View(df_us)
#merge
mergcountry = function(data1,data2){
data <- merge(x = data1, y = data2, by = "state", all.x = TRUE)
return(data)
}
data.top.state <- data.us.latest.top %>% filter(state != "US") %>%
select(state, confirmed, deaths)
#View(data.top.state)
df_Allus <- mergcountry(data.top.state, df_us_gender)
df_Allus <- mergcountry(df_Allus, df_us_pop)
df_Allus <- mergcountry(df_Allus, df_us_lockdown)
df_Allus <- mergcountry(df_Allus, df_us_gdp)
df_Allus <- mergcountry(df_Allus, df_us_homeless)
#View(df_Allus)
index <- is.na(df_Allus)
df_Allus[index] <- 0
#View(df_Allus)
normalize = function(data){
#return ((data - min(data,na.rm = TRUE))/(max(data,na.rm = TRUE) - min(data,na.rm = TRUE)))
z <- scale(data);
tanh(z/2)
}
Allus = as.data.frame(apply(df_Allus[,2:9],2,normalize))
corr_dataUS <- Allus
#View(corr_dataUS)
Allus$state <- c(df_Allus$state)
#View(Allus)
corr_dataUS <- rename(corr_dataUS ,"Daylockdown" = "Day lockdown")
Allus_plot <- select(Allus,"state","confirmed","deaths","Male","Female","Population","Day lockdown","GDPs","Homeless")
Allus_plot %<>% gather(key=type, value=count, -c(state))
level_order <- factor(Allus_plot$type,
level = c("confirmed","deaths","Male","Female","Population","Day lockdown","GDPs","Homeless"))
Allus_Heat <- Allus[,c(ncol(Allus),1:(ncol(Allus)-1))]
rownames(Allus_Heat) <- Allus_Heat[,1]
Allus_Heat[,1] <- NULL
heatmap.2(as.matrix(Allus_Heat),
scale="none",
col = colorRampPalette(c("#6D9EC1","white","#E46726"))(n = 200),
margins=c(10,6),trace="column")

heatmapus <- ggplot(data = Allus_plot, aes(x=state, y=level_order, fill=count)) +
geom_tile() +
scale_fill_gradient(low = "pink", high = "blue") +
xlab("") +
ylab("") +
theme_bw() +
theme(axis.text.x = element_text(angle = 90,vjust = 1))+
theme(
axis.line = element_blank(),
axis.ticks = element_blank(),
panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
panel.border = element_blank(),
panel.background = element_blank(),
#legend.position = "none"
) +labs(title='The heatmap of COVID-19 infections in US')
heatmapus

#correlation
corr_dataUS %<>% select(c(confirmed,deaths,Male,Female,Population,Daylockdown,GDPs,Homeless))
head(corr_dataUS)
cor(corr_dataUS)
confirmed deaths Male Female Population Daylockdown
confirmed 1.000000000 0.792654639 0.105367061 -0.005945092 0.959941301 -0.2058259
deaths 0.792654639 1.000000000 0.008041947 0.017335533 0.852691131 -0.3797468
Male 0.105367061 0.008041947 1.000000000 -0.877329594 -0.009961687 -0.2898630
Female -0.005945092 0.017335533 -0.877329594 1.000000000 0.069101784 0.3629328
Population 0.959941301 0.852691131 -0.009961687 0.069101784 1.000000000 -0.2155126
Daylockdown -0.205825865 -0.379746786 -0.289863040 0.362932815 -0.215512639 1.0000000
GDPs 0.910478267 0.884970609 -0.024379811 0.022358644 0.970528214 -0.3611378
Homeless 0.791615898 0.796426563 -0.080155515 0.151488777 0.863178014 -0.3573560
GDPs Homeless
confirmed 0.91047827 0.79161590
deaths 0.88497061 0.79642656
Male -0.02437981 -0.08015552
Female 0.02235864 0.15148878
Population 0.97052821 0.86317801
Daylockdown -0.36113782 -0.35735597
GDPs 1.00000000 0.89961070
Homeless 0.89961070 1.00000000
ggcorrplot(cor(corr_dataUS),hc.order = TRUE,
outline.color = "white",
colors = c("#6D9EC1","white","#E46726"),
lab = TRUE)

NA
NA
NA
#Covid_Thailand
df_thai <- tbl(my_db, sql("select * from covid19_thailand"))
df_thai <- as.data.frame(df_thai)
#View(df_thai)
#clean Covid_Thailand
dates.th <- df_thai[,2]%>% mdy()
range(dates.th)
[1] "2020-01-12" "2021-01-15"
min.date.th <- min(dates.th)
max.date.th <- max(dates.th)
min.date.txt.th <- min.date.th %>% format('%d %b %Y')
max.date.txt.th <- max.date.th %>% format('%d %b %Y')
df_thai$announce_date <- mdy(df_thai$announce_date)
df_thai$notification_date <- mdy(df_thai$notification_date)
df_thai
df_thai <- df_thai %>% select(!No.) %>% select(!notification_date) %>%
group_by(announce_date)
df_thai
View(df_thai)
# Total confirmed cases in Thailand
data.thai.count <- df_thai %>%
select(announce_date) %>%
summarise(confirmed = n()) %>% as.data.frame()
`summarise()` ungrouping output (override with `.groups` argument)
View(data.thai.count)
data.thai.count$cumulative_confirmed <- cumsum(data.thai.count[, 2])
data.thai.count <- data.thai.count %>% rename(new.confirmed=confirmed) %>% rename(confirmed=cumulative_confirmed)
thai.total.long <- data.thai.count %>%
gather(key = type, value = count, -c(announce_date))
thai.total.long
plot_thailand.conf <- thai.total.long %>%
filter(type %in% c("new.confirmed")) %>%
ggplot(aes(x = announce_date, y = count, color = type)) +
geom_line() +
xlab("Date") +
ylab("cases")
gly.plot_thai.cases <- ggplotly(plot_thailand.conf)
gly.plot_thai.cases <- gly.plot_thai.cases %>%
layout(title = paste0("<b>Daily Thai Confirmed Cases in Thailand : Jan 2020 - Jan 2021"),
font=list(size = 10))
gly.plot_thai.cases
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
plot_thailand.cumulative <- thai.total.long %>%
filter(type %in% c("confirmed")) %>%
ggplot(aes(x = announce_date, y = count)) +
geom_area(aes(fill=type), alpha=0.5) +
scale_y_continuous(trans='log10') +
scale_fill_manual(values=c('red'))+
ylab("") +
theme(axis.title = element_text(size=8))
gly.plot_thai.cumulative <- ggplotly(plot_thailand.cumulative)
gly.plot_thai.cumulative <- gly.plot_thai.cumulative %>%
layout(title = paste0("<b>Cumulative Cases in Thailand : Jan 2020 - Jan 2021 (Stack,Log scale)"),
font=list(size = 10))
gly.plot_thai.cumulative
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
## Thai Confirmed Cases (Jan 2020 - Jan 2021
plot1 <- ggplot(data.thai.count, aes(x=announce_date, y=confirmed)) +
geom_point() + geom_smooth() +
xlab(" ") + ylab("Count") + labs(title='Thai Cumulative Confirmed Cases (Jan 2020 - Jan 2021)') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot2 <- ggplot(data.thai.count, aes(x=announce_date, y=new.confirmed)) +
geom_point() + geom_smooth() +
xlab(" ") + ylab("Count")+ labs(title='Thai Confirmed Cases (Jan 2020 - Jan 2021 log scale)') +
theme(axis.text.x=element_text(angle=45, hjust=1))+scale_y_continuous(trans='log10')
## show two plots side by side
grid.arrange(plot1, plot2, ncol=1)

# Confirmed cases divided by sex (gender)
df_thai$sex[df_thai$sex == ""] <- "Unknown"
data.thai.gender <- df_thai %>%
group_by(sex) %>%
summarise(count = n()) %>%
mutate(percent = (count / sum(count) * 100) %>% round(2)) %>%
filter(percent>1)%>%
#mutate(pos = cumsum(percent) - 0.5*percent) %>%
arrange(desc(percent))
`summarise()` ungrouping output (override with `.groups` argument)
data.thai.gender
data.thai.gender$sex <- factor(data.thai.gender$sex, levels = as.character(data.thai.gender$sex))
data.thai.gender$sex
[1] Male Female
Levels: Male Female
g.th.gender <- data.thai.gender %>%
ggplot(aes(x = "", y = percent, fill = sex)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y") +
theme_void() +
labs(title='Gender of Thai Confirmed Cases (Jan 2020 - Jan 2021)')+
geom_text(aes(label = paste0(percent, "%")), color = "white", size = 5, position = position_stack(vjust = 0.5)) +
guides(fill = guide_legend(reverse = TRUE))
g.th.gender

# Confirmed cases divided by province_of_onset
data.thai.onset <- df_thai %>%
group_by(province_of_onset) %>%
summarise(count = n()) %>%
arrange(desc(count))%>%
rename(onset="count")%>%
rename(province="province_of_onset")
`summarise()` ungrouping output (override with `.groups` argument)
data.thai.onset$province[data.thai.onset$province == ""] <- "Unknown"
data.thai.onset
# Confirmed cases divided by province_of_isolation
data.thai.isolation <- df_thai %>%
group_by(province_of_isolation) %>%
summarise(count = n()) %>%
arrange(desc(count))%>%
rename(isolation ="count")%>%
rename(province="province_of_isolation")
`summarise()` ungrouping output (override with `.groups` argument)
data.thai.isolation$province[data.thai.isolation$province == ""] <- "Unknown"
data.thai.isolation
data.province <- merge(x = data.thai.onset, y = data.thai.isolation, by = "province", all.x = TRUE)
data.province <- data.province%>%filter(onset>125)
data.province
data.province.long <- data.province %>%
gather(key=type, value=count, -c(province))
data.province.long
province.thai <- ggplot(data.province.long,aes(x=province,y=count))+
geom_bar(stat = "identity",position = "dodge",aes(fill=type))+
labs(title = "Province of onset and Province of isolation in Thailand")+
theme(legend.title=element_blank(),
#legend.position='none',
plot.title=element_text(size=12),
axis.text=element_text(size=10),
axis.text.x=element_text(angle=45, hjust=1))+ xlab('') + ylab('Count')
gly.province.thai <- ggplotly(province.thai)
gly.province.thai
<<<<<<< .merge_file_a05344
=======
>>>>>>> .merge_file_a10112
# Confirmed cases divided by risk
data.thai.risk <- df_thai %>%
group_by(risk) %>%
summarise(count = n()) %>%
arrange(desc(count))
`summarise()` ungrouping output (override with `.groups` argument)
data.thai.risk
# Confirmed cases divided by risk
data.thai.risk <- df_thai %>%
group_by(risk) %>%
summarise(count = n()) %>%
mutate(percent = (count / sum(count) * 100) %>% round(2)) %>%
filter(percent>4) %>%
arrange(desc(percent))
`summarise()` ungrouping output (override with `.groups` argument)
data.thai.risk
data.thai.risk$risk[data.thai.risk$risk == "C"] <- "Close contact with the patient"
data.thai.risk$risk[data.thai.risk$risk == "CGustDr Samut SaGGAF"] <- "Cluster Samut Sakhon"
data.thai.risk$risk[data.thai.risk$risk == "F"] <- "State Quarantine"
data.thai.risk$risk[data.thai.risk$risk == "G"] <- "Go to a crowded place"
data.thai.risk$risk[data.thai.risk$risk == "A"] <- "People travelling from abroad"
data.thai.risk$risk[data.thai.risk$risk == "UFGFAwF"] <- "Unknown"
data.thai.risk$risk[data.thai.risk$risk == "D"] <- "Career at risk"
data.thai.risk$risk[data.thai.risk$risk == "CGustDr RayAFg"] <- "Cluster Rayong"
data.thai.risk$risk[data.thai.risk$risk == "CGustDr Pattaya CasCFA"] <- "Cluster Pattaya Casino"
data.thai.risk$risk[data.thai.risk$risk == "CGustDr AFg TGAFg"] <- "Cluster Ang Thong"
data.thai.risk
data.thai.risk$risk <- factor(data.thai.risk$risk, levels = as.character(data.thai.risk$risk))
data.thai.risk$risk
[1] Close contact with the patient Cluster Samut Sakhon State Quarantine
[4] Go to a crowded place People travelling from abroad Unknown
[7] Career at risk Cluster Rayong
8 Levels: Close contact with the patient Cluster Samut Sakhon ... Cluster Rayong
g.th.risk <- data.thai.risk %>%
ggplot(aes(x = "", y = percent, fill = risk)) +
geom_bar(stat = "identity", width = 0.5) +
coord_polar("y") +
theme_void() +
labs(title='Risk of Thai Confirmed Cases(Jan 2020 - Jan 2021)')+
geom_text(aes(label = paste0(percent, "%")), color = "Black", size = 3, position = position_stack(vjust = 0.5)) +
guides(fill = guide_legend(reverse = TRUE))
g.th.risk

# Confirmed cases divided by age
data.thai.age <- df_thai %>%
group_by(age,sex) %>%
filter(age != 0)%>%
summarise(count = n()) %>%
arrange(desc(count))
`summarise()` regrouping output by 'age' (override with `.groups` argument)
data.thai.age
data.thai.age <- data.thai.age# %>% filter(sex != "Unknown")
ggplot(data.thai.age,aes(x=age,y=count,fill=sex))+geom_bar(stat = "identity")+
labs(title='Age of Thai Confirmed Cases (Stack)')+guides(fill=guide_legend(reverse = T))

# Confirmed cases divided by nationality
data.thai.nationality <- df_thai
data.thai.nationality$nationality[data.thai.nationality$nationality == "????????"] <- "Unknown"
data.thai.nationality$nationality[data.thai.nationality$nationality == ""] <- "Unknown"
data.thai.nationality$nationality[data.thai.nationality$nationality == "Burma"] <- "Myanmar"
data.thai.nationality <- data.thai.nationality %>%
group_by(nationality) %>%
summarise(count = n()) %>%
filter(count > 11)%>%
arrange(desc(count))
`summarise()` ungrouping output (override with `.groups` argument)
data.thai.nationality
data.thai.nationality$count[data.thai.nationality$nationality == "Unknown"]
[1] 118
ggplot(data.thai.nationality, aes(x=reorder(nationality, count),y=count,fill = count))+
geom_bar(stat = "identity",show.legend = F)+
ggtitle('Nationality of Confirmed Cases in Thailand (log scale)')+
theme(plot.title = element_text(hjust = 0.5))+
theme(axis.text = element_text(size = 10),
axis.title = element_text(size = 10),
plot.title = element_text(size = 11))+
xlab("")+ylab("Number of Nationality")+
scale_y_continuous(trans='log10')+coord_flip()+scale_fill_gradient(low="blue",high = "red")

<<<<<<< .merge_file_a05344
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQojaW5zdGFsbC5wYWNrYWdlcygiZ3JpZCIpDQojaW5zdGFsbC5wYWNrYWdlcygiTUxSTVBBIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJkcHJlcCIpDQojaW5zdGFsbC5wYWNrYWdlcygibm9ybWFsciIpDQojaW5zdGFsbC5wYWNrYWdlcygiZ2djb3JycGxvdCIpDQojaW5zdGFsbC5wYWNrYWdlcygiUkNvbG9yQnJld2VyIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJyZ2RhbCIpDQojaW5zdGFsbC5wYWNrYWdlcygianNvbmxpdGUiKQ0KI2luc3RhbGwucGFja2FnZXMoIlJDb2xvckJyZXdlciIpDQojaW5zdGFsbC5wYWNrYWdlcygicmVhZHIiKQ0KU3lzLnNldGxvY2FsZSgiTENfQUxMIiwgIkVuZ2xpc2giKQ0KU3lzLnNldGVudigiTEFOR1VBR0UiPSJFbiIpDQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShtYWdyaXR0cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShub3JtYWxyKQ0KbGlicmFyeShnZ2NvcnJwbG90KQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCmxpYnJhcnkocmVhZHIpDQoNCiM/P3NyY19teXNxbA0KbXlfZGIgPC0gc3JjX215c3FsKA0KICBkYm5hbWUgPSAiY292aWQxOSIsDQogIGhvc3QgPSAiY3ZkLWRhdGFiYXNlLmNteHBueXlsaGtpdy51cy1lYXN0LTIucmRzLmFtYXpvbmF3cy5jb20iLA0KICB1c2VyID0gImFkbWluIiwNCiAgcGFzc3dvcmQgPSAiUnByb2plY3RDb3ZpZDE5Ig0KKQ0KbXlfZGINCg0KIyNpbXBvcnQgZGF0YQ0KZGZfY29uZiA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBjb3ZpZDE5X2NvbmZpcm1lZCIpKQ0KZGZfY29uZiA8LSBhcy5kYXRhLmZyYW1lKGRmX2NvbmYpDQpkZl9jb25mDQpkZl9kZWF0aHMgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gY292aWQxOV9kZWF0aHMiKSkNCmRmX2RlYXRocyA8LSBhcy5kYXRhLmZyYW1lKGRmX2RlYXRocykNCmRmX2RlYXRocw0KZGZfcmVjb3ZlciA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBjb3ZpZDE5X3JlY292ZXJlZCIpKQ0KZGZfcmVjb3ZlciA8LSBhcy5kYXRhLmZyYW1lKGRmX3JlY292ZXIpDQpkZl9yZWNvdmVyDQpgYGANCg0KYGBge3J9DQojI2NoZWNrIHRoZSB0aW1lIGZyYW1lIG9mIHRoZSBkYXRhDQpuLmNvbCA8LSBuY29sKGRmX2NvbmYpDQpkYXRlcyA8LSBuYW1lcyhkZl9jb25mKVs1Om4uY29sXSU+JSBtZHkoKQ0KcmFuZ2UoZGF0ZXMpDQptaW4uZGF0ZSA8LSBtaW4oZGF0ZXMpDQptYXguZGF0ZSA8LSBtYXgoZGF0ZXMpDQptaW4uZGF0ZS50eHQgPC0gbWluLmRhdGUgJT4lIGZvcm1hdCgnJWQgJWIgJVknKQ0KbWF4LmRhdGUudHh0IDwtIG1heC5kYXRlICU+JSBmb3JtYXQoJyVkICViICVZJykNCmBgYA0KYGBge3J9DQojY2xlYW4gZGF0YQ0KY2xlYW5EYXRhIDwtIGZ1bmN0aW9uKGRhdGEpIHsNCiAgIyMgcmVtb3ZlIHNvbWUgY29sdW1ucw0KICBkYXRhICU8PiUgc2VsZWN0KC1jKFByb3ZpbmNlLlN0YXRlLCBMYXQsIExvbmcpKSAlPiUgcmVuYW1lKGNvdW50cnk9Q291bnRyeS5SZWdpb24pDQogICMjIGNvbnZlcnQgZnJvbSB3aWRlIHRvIGxvbmcgZm9ybWF0DQogIGRhdGEgJTw+JSBnYXRoZXIoa2V5PWRhdGUsIHZhbHVlPWNvdW50LCAtY291bnRyeSkNCiAgIyMgY29udmVydCBmcm9tIGNoYXJhY3RlciB0byBkYXRlDQogIGRhdGEgJTw+JSBtdXRhdGUoZGF0ZSA9IGRhdGUgJT4lIG1keSgpKQ0KICAjIyBhZ2dyZWdhdGUgYnkgY291bnRyeQ0KICBkYXRhICU8PiUgZ3JvdXBfYnkoY291bnRyeSwgZGF0ZSkgJT4lIHN1bW1hcmlzZShjb3VudD1zdW0oY291bnQsIG5hLnJtPVQpKSAlPiUgYXMuZGF0YS5mcmFtZSgpDQogIHJldHVybihkYXRhKQ0KfQ0KIyMgY2xlYW4gdGhlIHRocmVlIGRhdGEgc2V0cw0KZGF0YS5jb25maXJtZWQgPC0gZGZfY29uZiAlPiUgY2xlYW5EYXRhKCkgJT4lIHJlbmFtZShjb25maXJtZWQ9Y291bnQpDQpkYXRhLmRlYXRocyA8LSBkZl9kZWF0aHMgJT4lIGNsZWFuRGF0YSgpICU+JSByZW5hbWUoZGVhdGhzPWNvdW50KQ0KZGF0YS5yZWNvdmVyZWQgPC0gZGZfcmVjb3ZlciAlPiUgY2xlYW5EYXRhKCkgJT4lIHJlbmFtZShyZWNvdmVyZWQ9Y291bnQpDQpkYXRhIDwtIGRhdGEuY29uZmlybWVkICU+JSBtZXJnZShkYXRhLmRlYXRocywgYWxsPVQpICU+JSBtZXJnZShkYXRhLnJlY292ZXJlZCwgYWxsPVQpDQpkYXRhDQojIyBjb3VudHJpZXMvcmVnaW9ucyB3aXRoIGNvbmZpcm1lZCBjYXNlcywgZXhjbC4gY3J1aXNlIHNoaXBzDQpjb3VudHJpZXMgPC0gZGF0YSAlPiUgcHVsbChjb3VudHJ5KSAlPiUgc2V0ZGlmZignQ3J1aXNlIFNoaXAnKQ0KZGF0YQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YS53b3JsZCA8LSBkYXRhICU+JSBncm91cF9ieShkYXRlKSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50cnk9J1dvcmxkJywNCiAgICAgICAgICAgIGNvbmZpcm1lZCA9IHN1bShjb25maXJtZWQsIG5hLnJtPVQpLA0KICAgICAgICAgICAgZGVhdGhzID0gc3VtKGRlYXRocywgbmEucm09VCksDQogICAgICAgICAgICByZWNvdmVyZWQgPSBzdW0ocmVjb3ZlcmVkLCBuYS5ybT1UKSkNCmRhdGEgJTw+JSByYmluZChkYXRhLndvcmxkKQ0KZGF0YQ0KZGF0YSAlPD4lIG11dGF0ZShjdXJyZW50LmNvbmZpcm1lZCA9IGNvbmZpcm1lZCAtIGRlYXRocyAtIHJlY292ZXJlZCkNCiNWaWV3KGRhdGEpDQpgYGANCg0KDQoNCmBgYHtyfQ0KIyBXb3JsZCBjb25maXJtZWQgY2FzZXMgbWFwDQp3b3JsZC5sb2NhdGlvbiA8LSBkZl9jb25mDQojVmlldyh3b3JsZC5sb2NhdGlvbiApDQp3b3JsZC5sb2NhdGlvbiRjb25maXJtZWQgPC0gd29ybGQubG9jYXRpb24gWywgbmNvbCh3b3JsZC5sb2NhdGlvbiApXQ0Kd29ybGQubG9jYXRpb24gICU8PiUgc2VsZWN0KGMoQ291bnRyeS5SZWdpb24sIFByb3ZpbmNlLlN0YXRlLCBMYXQsIExvbmcsIGNvbmZpcm1lZCkpICU+JQ0KICBtdXRhdGUodHh0PXBhc3RlMChDb3VudHJ5LlJlZ2lvbiwgJyAtICcsIFByb3ZpbmNlLlN0YXRlLCAnOiAnLCBjb25maXJtZWQpKQ0KbWFwLmNvbmZpcm1lZCA8LSBsZWFmbGV0KHdpZHRoPTEyMDAsIGhlaWdodD04MDApICU+JSBhZGRUaWxlcygpDQojIGNpcmNsZSBtYXJrZXIgKHVuaXRzIGluIHBpeGVscykNCm1hcC5jb25maXJtZWQgJTw+JSBhZGRDaXJjbGVNYXJrZXJzKHdvcmxkLmxvY2F0aW9uJExvbmcsIHdvcmxkLmxvY2F0aW9uJExhdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICMgcmFkaXVzPTIrbG9nMih4JGNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgICAgICAgICByYWRpdXM9MC4wMipzcXJ0KHdvcmxkLmxvY2F0aW9uJGNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgICAgICAgICBzdHJva2U9RiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPSdyZWQnLCBmaWxsT3BhY2l0eT0wLjMsDQogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD13b3JsZC5sb2NhdGlvbiR0eHQpDQojIHdvcmxkDQptYXAuY29uZmlybWVkDQpgYGANCg0KYGBge3J9DQojIyBDaGluYQ0KbWFwLmNvbmZpcm1lZCAlPiUgc2V0Vmlldyg5NSwgMzUsIHpvb209NCkNCiMjIEF1c3RyYWxpYSBhbmQgTmV3IFplYWxhbmQNCm1hcC5jb25maXJtZWQgJT4lIHNldFZpZXcoMTM1LCAtMjcsIHpvb209NCkNCiMjIFVTIGFuZCBDYW5hZGENCm1hcC5jb25maXJtZWQgJT4lIHNldFZpZXcoLTEwNSwgNDAsIHpvb209NCkNCiMjIEV1cm9wZQ0KbWFwLmNvbmZpcm1lZCAlPiUgc2V0VmlldygxMCwgNTAsIHpvb209NCkNCmBgYA0KDQpgYGB7cn0NCiMgbmV3LmNvbmZpcm1lZCBuZXcuZGVhdGhzIG5ldy5yZWNvdmVyZWQNCmRhdGEgJTw+JSBhcnJhbmdlKGNvdW50cnksIGRhdGUpDQpuIDwtIG5yb3coZGF0YSkNCmRheTEgPC0gbWluKGRhdGEkZGF0ZSkNCmRhdGEgJTw+JSBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCBjb25maXJtZWQgLSBsYWcoY29uZmlybWVkLCBuPTEpKSwNCiAgICAgICAgICAgICAgICAgbmV3LmRlYXRocyA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCBkZWF0aHMgLSBsYWcoZGVhdGhzLCBuPTEpKSwNCiAgICAgICAgICAgICAgICAgbmV3LnJlY292ZXJlZCA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCByZWNvdmVyZWQgLSBsYWcocmVjb3ZlcmVkLCBuPTEpKSkNCmRhdGEgJTw+JSBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShuZXcuY29uZmlybWVkIDwgMCwgMCwgbmV3LmNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgIG5ldy5kZWF0aHMgPSBpZmVsc2UobmV3LmRlYXRocyA8IDAsIDAsIG5ldy5kZWF0aHMpLA0KICAgICAgICAgICAgICAgICBuZXcucmVjb3ZlcmVkID0gaWZlbHNlKG5ldy5yZWNvdmVyZWQgPCAwLCAwLCBuZXcucmVjb3ZlcmVkKSkNCiMjIGRlYXRoIHJhdGUgYmFzZWQgb24gdG90YWwgZGVhdGhzIGFuZCByZWNvdmVyZWQgY2FzZXMNCmRhdGEgJTw+JSBtdXRhdGUocmF0ZS51cHBlciA9ICgxMDAgKiBkZWF0aHMgLyAoZGVhdGhzICsgcmVjb3ZlcmVkKSkgJT4lIHJvdW5kKDEpLA0KICAgICAgICAgICAgICAgICByYXRlLnVwcGVyID0gaWZlbHNlKGlzLm5hbihyYXRlLnVwcGVyKSwgMCwgcmF0ZS51cHBlcikpDQoNCiMjIGxvd2VyIGJvdW5kOiBkZWF0aCByYXRlIGJhc2VkIG9uIHRvdGFsIGNvbmZpcm1lZCBjYXNlcw0KZGF0YSAlPD4lIG11dGF0ZShyYXRlLmxvd2VyID0gKDEwMCAqIGRlYXRocyAvIGNvbmZpcm1lZCkgJT4lIHJvdW5kKDEpLA0KICAgICAgICAgICAgICAgICByYXRlLmxvd2VyID0gaWZlbHNlKGlzLm5hbihyYXRlLmxvd2VyKSwgMCwgcmF0ZS5sb3dlcikpDQoNCiMjIGRlYXRoIHJhdGUgYmFzZWQgb24gdGhlIG51bWJlciBvZiBkZWF0aC9yZWNvdmVyZWQgb24gZXZlcnkgc2luZ2xlIGRheQ0KZGF0YSAlPD4lIG11dGF0ZShyYXRlLmRhaWx5ID0gKDEwMCAqIG5ldy5kZWF0aHMgLyAobmV3LmRlYXRocyArIG5ldy5yZWNvdmVyZWQpKSAlPiUgcm91bmQoMSksDQogICAgICAgICAgICAgICAgIHJhdGUuZGFpbHkgPSBpZmVsc2UoaXMubmFuKHJhdGUuZGFpbHkpLCAwLCByYXRlLmRhaWx5KSkNCg0KI1ZpZXcoZGF0YSkNCmBgYA0KDQpgYGB7cn0NCiMjIGNvbnZlcnQgZnJvbSB3aWRlIHRvIGxvbmcgZm9ybWF0DQpkYXRhLmxvbmcgPC0gZGF0YSAlPiUNCiAgc2VsZWN0KGMoY291bnRyeSwgZGF0ZSwgY29uZmlybWVkLCBjdXJyZW50LmNvbmZpcm1lZCwgcmVjb3ZlcmVkLCBkZWF0aHMpKSAlPiUNCiAgZ2F0aGVyKGtleT10eXBlLCB2YWx1ZT1jb3VudCwgLWMoY291bnRyeSwgZGF0ZSkpDQojIyBzZXQgZmFjdG9yIGxldmVscyB0byBzaG93IHRoZW0gaW4gYSBkZXNpcmFibGUgb3JkZXINCmRhdGEubG9uZyAlPD4lIG11dGF0ZSh0eXBlPXJlY29kZV9mYWN0b3IodHlwZSwgY29uZmlybWVkPSdUb3RhbCBDb25maXJtZWQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50LmNvbmZpcm1lZD0nQ3VycmVudCBDb25maXJtZWQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNvdmVyZWQ9J1JlY292ZXJlZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlYXRocz0nRGVhdGhzJykpDQojVmlldyhkYXRhLmxvbmcpDQpgYGANCg0KYGBge3J9DQojI051bWJlciBvZiBjYXNlIFdvcmxkDQp3b3JsZCA8LSBmaWx0ZXIoZGF0YS5sb25nLGNvdW50cnkgPT0gJ1dvcmxkJykNCndvcmxkDQpwbG90X3dvcmxkLmFyZWEgPC0gd29ybGQgJT4lIGZpbHRlcih0eXBlICE9ICdUb3RhbCBDb25maXJtZWQnKSAlPiUNCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9Y291bnQpKSArDQogIGdlb21fYXJlYShhZXMoZmlsbD10eXBlKSwgYWxwaGE9MC41KSArDQogIGxhYnModGl0bGU9cGFzdGUwKCdOdW1iZXJzIG9mIENhc2VzIFdvcmxkd2lkZSAtICcsIG1heC5kYXRlLnR4dCkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoJ3JlZCcsICdncmVlbicsICdibGFjaycpKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj0nYm90dG9tJywNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTcpLA0KICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQua2V5LnNpemU9dW5pdCgwLjIsICdjbScpLA0KICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT02KSwNCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTcpLA0KICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdF93b3JsZC5saW5lIDwtIHdvcmxkICU+JQ0KICBnZ3Bsb3QoYWVzKHg9ZGF0ZSwgeT1jb3VudCxjb2xvciA9IHR5cGUpKSArDQogIGdlb21fbGluZShhZXMoY29sb3I9dHlwZSkpICsNCiAgbGFicyh0aXRsZT1wYXN0ZTAoJ051bWJlcnMgb2YgQ2FzZXMgV29ybGR3aWRlIChsb2cgc2NhbGUpIC0gJywgbWF4LmRhdGUudHh0KSkgKw0KICAjc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCdibHVlJywgJ3JlZCcsICdncmVlbicsICdibGFjaycpKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj0nYm90dG9tJywNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTcpLA0KICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQua2V5LnNpemU9dW5pdCgwLjIsICdjbScpLA0KICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT02KSwNCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTcpLA0KICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKSArDQogIHNjYWxlX3lfY29udGludW91cyh0cmFucz0nbG9nMTAnKQ0KIyMgc2hvdyB0d28gcGxvdHMgc2lkZSBieSBzaWRlDQpncmlkLmFycmFuZ2UocGxvdF93b3JsZC5hcmVhLCBwbG90X3dvcmxkLmxpbmUsIG5jb2w9MikNCg0KZ2x5LnBsb3Rfd29ybGQuYXJlYSA8LSBnZ3Bsb3RseShwbG90X3dvcmxkLmFyZWEpDQpnbHkucGxvdF93b3JsZC5hcmVhDQoNCmdseS5wbG90X3dvcmxkLmxpbmUgPC0gZ2dwbG90bHkocGxvdF93b3JsZC5saW5lKQ0KZ2x5LnBsb3Rfd29ybGQubGluZQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmRhdGEud29ybGQuYWxsIDwtIGRhdGEgJT4lIGZpbHRlcihjb3VudHJ5ID09ICJXb3JsZCIpDQojIyBhIHNjYXR0ZXIgcGxvdCB3aXRoIGEgc21vb3RoZWQgbGluZSBhbmQgdmVydGljYWwgeC1heGlzIGxhYmVscw0KcGxvdF9hY2MuZGVhdGhzIDwtIGdncGxvdChkYXRhLndvcmxkLmFsbCwgYWVzKHg9ZGF0ZSwgeT1kZWF0aHMpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdBY2N1bXVsYXRpdmUgRGVhdGhzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdF9yZWNvdmVyZWQgPC0gZ2dwbG90KGRhdGEud29ybGQuYWxsLCBhZXMoeD1kYXRlLCB5PXJlY292ZXJlZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J0FjY3VtdWxhdGl2ZSBSZWNvdmVyZWQgQ2FzZXMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQpwbG90X25ldy5kZWF0aHMgPC0gZ2dwbG90KGRhdGEud29ybGQuYWxsLCBhZXMoeD1kYXRlLCB5PW5ldy5kZWF0aHMpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdOZXcgRGVhdGhzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdF9uZXcucmVjb3ZlcmVkIDwtIGdncGxvdChkYXRhLndvcmxkLmFsbCwgYWVzKHg9ZGF0ZSwgeT1uZXcucmVjb3ZlcmVkKSkgKw0KICBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aCgpICsNCiAgeGxhYignJykgKyB5bGFiKCdDb3VudCcpICsgbGFicyh0aXRsZT0nTmV3IFJlY292ZXJlZCBDYXNlcycpICsNCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkNCiMjIHNob3cgZm91ciBwbG90cyB0b2dldGhlciwgd2l0aCAyIHBsb3RzIGluIGVhY2ggcm93DQpncmlkLmFycmFuZ2UocGxvdF9hY2MuZGVhdGhzLCBwbG90X3JlY292ZXJlZCwgcGxvdF9uZXcuZGVhdGhzLCBwbG90X25ldy5yZWNvdmVyZWQsIG5yb3c9MikNCg0KYGBgDQoNCmBgYHtyfQ0KIyMgY29udmVydCBmcm9tIHdpZGUgdG8gbG9uZyBmb3JtYXQsIGZvciBkcmF3aW5nIGFyZWEgcGxvdHMNCnJhdGVzLmxvbmcgPC0gZGF0YSAlPiUNCiAgc2VsZWN0KGMoY291bnRyeSwgZGF0ZSwgcmF0ZS51cHBlciwgcmF0ZS5sb3dlciwgcmF0ZS5kYWlseSkpICU+JQ0KICBnYXRoZXIoa2V5PXR5cGUsIHZhbHVlPWNvdW50LCAtYyhjb3VudHJ5LCBkYXRlKSkNCiMgc2V0IGZhY3RvciBsZXZlbHMgdG8gc2hvdyB0aGVtIGluIGEgZGVzaXJhYmxlIG9yZGVyDQpyYXRlcy5sb25nICU8PiUgbXV0YXRlKHR5cGU9cmVjb2RlX2ZhY3Rvcih0eXBlLCByYXRlLmRhaWx5PSdEYWlseScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhdGUudXBwZXI9J1VwcGVyIGJvdW5kJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmF0ZS5sb3dlciA9ICdMb3dlciBib3VuZCcpKSANCiNWaWV3KHJhdGVzLmxvbmcpIA0KDQpwbG90X3JhdGVzIDwtIHJhdGVzLmxvbmcgJT4lIGZpbHRlcihjb3VudHJ5ID09ICJXb3JsZCIpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IGNvdW50LCBjb2xvciA9IHR5cGUpKSArIA0KICBnZW9tX2xpbmUoKSArDQogIGxhYnModGl0bGUgPSAiV29ybGQgRGVhdGggUmF0ZSAoJSkiKSArDQogIHhsYWIoIiIpICsgeWxhYigiRGVhdGggUmF0ZSAoJSkiKQ0KDQpwbG90X3JhdGVzDQoNCmdseS5yYXRlcyA8LSBnZ3Bsb3RseShwbG90X3JhdGVzKQ0KZ2x5LnJhdGVzDQpgYGANCg0KYGBge3J9DQojIyByYW5raW5nIGJ5IGNvbmZpcm1lZCBjYXNlcw0KZGF0YS5sYXRlc3QuYWxsIDwtIGRhdGEgJT4lIGZpbHRlcihkYXRlID09IG1heChkYXRlKSkgJT4lDQogIHNlbGVjdChjb3VudHJ5LCBkYXRlLGNvbmZpcm1lZCwgbmV3LmNvbmZpcm1lZCwgY3VycmVudC5jb25maXJtZWQsDQogICAgICAgICByZWNvdmVyZWQsIGRlYXRocywgbmV3LmRlYXRocywgZGVhdGgucmF0ZT1yYXRlLmxvd2VyKSAlPiUNCiAgbXV0YXRlKHJhbmtpbmcgPSBkZW5zZV9yYW5rKGRlc2MoY29uZmlybWVkKSkpICU+JQ0KICBhcnJhbmdlKHJhbmtpbmcpDQojVmlldyhkYXRhLmxhdGVzdC5hbGwpDQoNCmsgPC0gMjANCiMjIHRvcCAyMCBjb3VudHJpZXM6IDIxIGluY2wuICdXb3JsZCcNCnRvcC5jb3VudHJpZXMgPC0gZGF0YS5sYXRlc3QuYWxsICU+JSBmaWx0ZXIocmFua2luZyA8PSBrICsgMSkgJT4lDQogIGFycmFuZ2UocmFua2luZykgJT4lIHB1bGwoY291bnRyeSkgJT4lIGFzLmNoYXJhY3RlcigpDQp0b3AuY291bnRyaWVzICU+JSBzZXRkaWZmKCdXb3JsZCcpICU+JSBwcmludCgpDQpgYGANCg0KDQpgYGB7cn0NCmRmIDwtIGRhdGEubG9uZyAlPiUgZmlsdGVyKGNvdW50cnkgJWluJSB0b3AuY291bnRyaWVzKSAlPiUNCiAgbXV0YXRlKGNvdW50cnk9Y291bnRyeSAlPiUgZmFjdG9yKGxldmVscz1jKHRvcC5jb3VudHJpZXMpKSkgJT4lIA0KICBmaWx0ZXIoY291bnRyeSAhPSAnV29ybGQnICYgdHlwZSAhPSAnVG90YWwgQ29uZmlybWVkJykgJT4lDQogIGdncGxvdChhZXMoeD1kYXRlLCB5PWNvdW50LCBjb2xvcj10eXBlKSkgKw0KICBnZW9tX2xpbmUoKSsNCiAgI2dlb21fYXJlYShhbHBoYT0wLjUpICsNCiMgeGxhYignJykgKyB5bGFiKCcnKSArDQogIGxhYnModGl0bGU9cGFzdGUwKCdOdW1iZXJzIG9mIENPVklELTE5IENhc2VzIGluIFRvcCAyMCBDb3VudHJpZXMgLSAnLA0KICAgICAgICAgICAgICAgICAgICBtYXguZGF0ZS50eHQpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygncmVkJywgJ2dyZWVuJywgJ2JsYWNrJykpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uPSdib3R0b20nLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTIpLA0KICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQua2V5LnNpemU9dW5pdCgwLjQsICdjbScpLA0KICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMiksDQogICAgICAgIHN0cmlwLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiksDQogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMiksDQogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpICsNCiAgZmFjZXRfd3JhcCh+Y291bnRyeSwgbmNvbD00LCBzY2FsZXM9J2ZyZWVfeScpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSdsb2cxMCcpDQpkZg0KYGBgDQoNCmBgYHtyfQ0KZGF0YS5sYXRlc3QgPC0gZGF0YS5sYXRlc3QuYWxsICU+JSBmaWx0ZXIoIWlzLm5hKGNvdW50cnkpKSAlPiUNCiAgbXV0YXRlKGNvdW50cnk9aWZlbHNlKHJhbmtpbmcgPD0gayArIDEsIGFzLmNoYXJhY3Rlcihjb3VudHJ5KSwgJ090aGVycycpKSAlPiUNCiAgbXV0YXRlKGNvdW50cnk9Y291bnRyeSAlPiUgZmFjdG9yKGxldmVscz1jKHRvcC5jb3VudHJpZXMsICdPdGhlcnMnKSkpDQpkYXRhLmxhdGVzdCAlPD4lIGdyb3VwX2J5KGNvdW50cnkpICU+JQ0KICBzdW1tYXJpc2UoY29uZmlybWVkPXN1bShjb25maXJtZWQpLCBuZXcuY29uZmlybWVkPXN1bShuZXcuY29uZmlybWVkKSwNCiAgICAgICAgICAgIGN1cnJlbnQuY29uZmlybWVkPXN1bShjdXJyZW50LmNvbmZpcm1lZCksDQogICAgICAgICAgICByZWNvdmVyZWQ9c3VtKHJlY292ZXJlZCksIGRlYXRocz1zdW0oZGVhdGhzKSwgbmV3LmRlYXRocz1zdW0obmV3LmRlYXRocykpICU+JQ0KICBtdXRhdGUoZGVhdGgucmF0ZT0oMTAwICogZGVhdGhzL2NvbmZpcm1lZCkgJT4lIHJvdW5kKDEpKSANCmRhdGEubGF0ZXN0DQpkYXRhLmxhdGVzdCAlPD4lIHNlbGVjdChjKGNvdW50cnksIGNvbmZpcm1lZCwgZGVhdGhzLCBkZWF0aC5yYXRlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcuY29uZmlybWVkLCBuZXcuZGVhdGhzLCBjdXJyZW50LmNvbmZpcm1lZCxyZWNvdmVyZWQpKSAlPiUNCiAgbXV0YXRlKHJlY292ZXIucmF0ZT0oMTAwICogcmVjb3ZlcmVkL2NvbmZpcm1lZCkgJT4lIHJvdW5kKDEpKQ0KZGF0YS5sYXRlc3QNCm1vc3Rjb25maXJtIDwtIGRhdGEubGF0ZXN0ICU+JSBzZWxlY3QoYyhjb3VudHJ5LGNvbmZpcm1lZCkpICU+JSBmaWx0ZXIoY291bnRyeT09IldvcmxkIikNCm1vc3RyZWNvdmVyIDwtIGRhdGEubGF0ZXN0ICU+JSBzZWxlY3QoYyhjb3VudHJ5LHJlY292ZXJlZCkpICU+JSBmaWx0ZXIoY291bnRyeT09IldvcmxkIikNCm1vc3RkZWF0aCA8LSBkYXRhLmxhdGVzdCAlPiUgc2VsZWN0KGMoY291bnRyeSxkZWF0aHMpKSAlPiUgZmlsdGVyKGNvdW50cnk9PSJXb3JsZCIpDQoNCmRmX3BvcCA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBwb3B1bGF0aW9uICIpKQ0KZGZfcG9wIDwtIGFzLmRhdGEuZnJhbWUoZGZfcG9wKQ0KZGZfcG9wIDwtIHJlbmFtZShkZl9wb3AsImNvdW50cnkiPSJDb3VudHJ5IikNCg0KIyBBZGQgV29ybGQgUG9wdWxhdGlvbg0Kd29ybGRfcG9wIDwtIHN1bShkZl9wb3AkYFBvcHVsYXRpb24gKDIwMjApYCkNCmRmX3BvcFtucm93KGRmX3BvcCkgKyAxLF0gPSBjKCJXb3JsZCIsIHdvcmxkX3BvcCkNCg0KIyBBZGQgT3RoZXIgQ291bnRyaWVzIFBvcHVsYXRpb24NCnRvcF9wb3AgPC0gZmlsdGVyKGRmX3BvcCwgZGZfcG9wJGNvdW50cnkgJWluJSB0b3AuY291bnRyaWVzICYgZGZfcG9wJGNvdW50cnkgIT0gIldvcmxkIikNCnRvcF9wb3AgPC0gc3VtKHRvcF9wb3AkYFBvcHVsYXRpb24gKDIwMjApYCAlPiUgYXMubnVtZXJpYygpKQ0Kb3RoZXJzX3BvcCA8LSAod29ybGRfcG9wIC0gdG9wX3BvcCkgDQpkZl9wb3BbbnJvdyhkZl9wb3ApICsgMSxdID0gYygiT3RoZXJzIiwgb3RoZXJzX3BvcCkNCiNWaWV3KGRmX3BvcCkNCg0KZGF0YS5sYXRlc3QgPC0gbWVyZ2UoeCA9IGRhdGEubGF0ZXN0LCB5ID0gZGZfcG9wLCBieSA9ICJjb3VudHJ5IiwgYWxsLnggPSBUUlVFKSANCmRhdGEubGF0ZXN0DQpkYXRhLmxhdGVzdCA8LSByZW5hbWUoZGF0YS5sYXRlc3QsInBvcHVsYXRpb24iID0gIlBvcHVsYXRpb24gKDIwMjApIikNCmRhdGEubGF0ZXN0JHBvcHVsYXRpb24gPC0gZGF0YS5sYXRlc3QkcG9wdWxhdGlvbiAlPiUgYXMubnVtZXJpYygpDQpkYXRhLmxhdGVzdCAgPC0gZGF0YS5sYXRlc3QgJT4lDQogIHNlbGVjdChjKGNvdW50cnksIGNvbmZpcm1lZCwgZGVhdGhzLCBkZWF0aC5yYXRlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcuY29uZmlybWVkLCBuZXcuZGVhdGhzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50LmNvbmZpcm1lZCwgcmVjb3ZlcmVkLCByZWNvdmVyLnJhdGUsIHBvcHVsYXRpb24pKSAlPiUNCiAgbXV0YXRlKGNvbmZpcm0ucmF0ZSA9ICgxMDAgKiBjb25maXJtZWQgLyBwb3B1bGF0aW9uKSAlPiUgcm91bmQoMSkpDQpkYXRhLmxhdGVzdA0KYGBgDQoNCmBgYHtyfQ0KIyMgJSBvZiBkZWF0aA0KZGF0YS5sYXRlc3QgJT4lIG11dGF0ZShkZWF0aC5yYXRlPWRlYXRoLnJhdGUgJT4lIGZvcm1hdChuc21hbGw9MSkgJT4lIHBhc3RlMCgnJScpKQ0KDQojIyBjb252ZXJ0IGZyb20gd2lkZSB0byBsb25nIGZvcm1hdCwgZm9yIGRyYXdpbmcgYXJlYSBwbG90cw0KZGF0YS5sYXRlc3QubG9uZyA8LSBkYXRhLmxhdGVzdCAlPiUgZmlsdGVyKGNvdW50cnkhPSdXb3JsZCcpICU+JQ0KICBnYXRoZXIoa2V5PXR5cGUsIHZhbHVlPWNvdW50LCAtY291bnRyeSkNCiMjIHNldCBmYWN0b3IgbGV2ZWxzIHRvIHNob3cgdGhlbSB3aXRoIHByb3BlciB0ZXh0IGFuZCBpbiBhIGRlc2lyYWJsZSBvcmRlcg0KZGF0YS5sYXRlc3QubG9uZyAlPD4lIG11dGF0ZSh0eXBlPXJlY29kZV9mYWN0b3IodHlwZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpcm1lZD0nVG90YWwgQ29uZmlybWVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlYXRocz0nVG90YWwgRGVhdGhzJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlYXRoLnJhdGU9J0RlYXRoIFJhdGUgKCUpJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldy5jb25maXJtZWQ9J05ldyBDb25maXJtZWQgKGNvbXBhcmVkIHdpdGggb25lIGRheSBiZWZvcmUpJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldy5kZWF0aHM9J05ldyBEZWF0aHMgKGNvbXBhcmVkIHdpdGggb25lIGRheSBiZWZvcmUpJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnQuY29uZmlybWVkPSdDdXJyZW50IENvbmZpcm1lZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNvdmVyLnJhdGUgPSAnUmVjb3ZlcmVkIFJhdGUoJSknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlybS5yYXRlID0gJ0NvbmZpcm1lZCBSYXRlKCUpJykpDQojVmlldyhkYXRhLmxhdGVzdC5sb25nKQ0KZGF0YS5vbmUuZGVtIDwtIGZpbHRlcihkYXRhLmxhdGVzdC5sb25nLHR5cGU9PSdUb3RhbCBDb25maXJtZWQnDQogICAgICAgICAgICAgICAgICAgICAgIHwgdHlwZT09J1RvdGFsIERlYXRocycNCiAgICAgICAgICAgICAgICAgICAgICAgfCB0eXBlPT0nQ3VycmVudCBDb25maXJtZWQnKQ0KZGF0YS50d28uZGVtIDwtIGZpbHRlcihkYXRhLmxhdGVzdC5sb25nLHR5cGU9PSdEZWF0aCBSYXRlICglKScNCiAgICAgICAgICAgICAgICAgICAgICMgIHwgdHlwZT09J05ldyBDb25maXJtZWQgKGNvbXBhcmVkIHdpdGggb25lIGRheSBiZWZvcmUpJw0KICAgICAgICAgICAgICAgICAgICAjICAgfCB0eXBlPT0nTmV3IERlYXRocyAoY29tcGFyZWQgd2l0aCBvbmUgZGF5IGJlZm9yZSknDQogICAgICAgICAgICAgICAgICAgICAgIHwgdHlwZT09J1JlY292ZXJlZCBSYXRlKCUpJw0KICAgICAgICAgICAgICAgICAgICAgICB8IHR5cGU9PSdDb25maXJtZWQgUmF0ZSglKScpDQpkYXRhLnR3by5kZW0NCmBgYA0KDQpgYGB7cn0NCiMjIGJhciBjaGFydA0KZGF0YS5vbmUuZGVtICU+JSBnZ3Bsb3QoYWVzKHg9Y291bnRyeSwgeT1jb3VudCwgZmlsbD1jb3VudHJ5LCBncm91cD1jb3VudHJ5KSkgKw0KICBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1jb3VudCwgeT1jb3VudCksIHNpemU9Mywgdmp1c3Q9MCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJycpICsNCiAgbGFicyh0aXRsZT1wYXN0ZTAoJ1RvcCAyMCBDb3VudHJpZXMgd2l0aCBNb3N0IENvbmZpcm1lZCBDYXNlcyAtICcsIG1heC5kYXRlLnR4dCkpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lPSdDb3VudHJ5JywgbGFiZWxzPWFlcyhjb3VudCkpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSdub25lJywNCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMyksDQogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkgKw0KICBmYWNldF93cmFwKH50eXBlLCBuY29sPTEsIHNjYWxlcz0nZnJlZV95JykNCmBgYA0KDQpgYGB7cn0NCmRhdGEudHdvLmRlbSRmYWNldCA8LSBmYWN0b3IoZGF0YS50d28uZGVtJHR5cGUsIGxldmVscyA9IGMoJ0NvbmZpcm1lZCBSYXRlKCUpJywgJ1JlY292ZXJlZCBSYXRlKCUpJywnRGVhdGggUmF0ZSAoJSknKSkNCmRhdGEudHdvLmRlbSAlPiUgDQogIGdncGxvdChhZXMoeD1jb3VudHJ5LCB5PWNvdW50LCBmaWxsPWNvdW50cnksIGdyb3VwPWNvdW50cnkpKSArDQogIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPWNvdW50LCB5PWNvdW50KSwgc2l6ZT00LCB2anVzdD0wKSArDQogIHhsYWIoJycpICsgeWxhYignJykgKw0KICBsYWJzKHRpdGxlPXBhc3RlMCgnVG9wIDIwIENvdW50cmllcyB3aXRoIE1vc3QgQ29uZmlybWVkIENhc2VzIC0gJywgbWF4LmRhdGUudHh0KSkgKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWU9J0NvdW50cnknLCBsYWJlbHM9YWVzKGNvdW50KSkgKw0KICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb249J25vbmUnLA0KICAgICAgICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEzKSwNCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEwKSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTAsYW5nbGU9NDUsIGhqdXN0PTEpKSArDQogIGZhY2V0X3dyYXAofmZhY2V0LCBuY29sPTEsIHNjYWxlcz0nZnJlZV95JykNCmBgYA0KDQpgYGB7cn0NCiMjR0RQDQpkZl9nZHAyMDE5IDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGdkcDE5IikpDQpkZl9nZHAyMDE5IDwtIGFzLmRhdGEuZnJhbWUoZGZfZ2RwMjAxOSkNCmRmX2dkcDIwMTkNCmBgYA0KDQpgYGB7cn0NCiNoZWFsdGhyYW5raW5nIGRhdGENCmRmX2hlYWx0IDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGhlYWx0aHJhbmtpbmciKSkNCmRmX2hlYWx0IDwtIGFzLmRhdGEuZnJhbWUoZGZfaGVhbHQpDQpkZl9oZWFsdCA8LSBzZWxlY3QoZGZfaGVhbHQsYygiY291bnRyeSIsImhlYWx0aENhcmVJbmRleCIpKQ0KI1ZpZXcoZGZfaGVhbHQpDQpgYGANCg0KYGBge3J9DQojVG9wMjBQb3JuaHViIGRhdGENCiNkZl9wb3JuaHViIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIFBvcm5odWIiKSkNCiNkZl9wb3JuaHViIDwtIGFzLmRhdGEuZnJhbWUoZGZfcG9ybmh1YikNCiNkZl9wb3JuaHViDQpgYGANCg0KYGBge3J9DQojIHRlbXAgZGF0YQ0KZGZfdGVtcCA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSB3b3JsZF90ZW1wIikpDQpkZl90ZW1wIDwtIGFzLmRhdGEuZnJhbWUoZGZfdGVtcCkgDQpkZl90ZW1wJENvdW50cnlbZGZfdGVtcCRDb3VudHJ5ID09ICJVbml0ZWQgU3RhdGVzIl0gPC0gIlVTIg0KDQpkZl9jaXR5IDwtIHNlbGVjdChkZl90ZW1wLGMoIkNvdW50cnkiLCJDaXR5IikpICU+JQ0KICByZW5hbWUoY291bnRyeT1Db3VudHJ5KSAlPiUgDQogIHJlbmFtZShjaXR5PUNpdHkpDQoNCm51bW9mY2l0eSA8LSBhZ2dyZWdhdGUoY2l0eSB+IGNvdW50cnksIGRhdGEgPSBkZl9jaXR5LCBsZW5ndGgpDQoNCiNjbGVhbiBkYXRhDQpkZl90ZW1wIDwtIHNlbGVjdChkZl90ZW1wLGMoIkNvdW50cnkiLCJBdmdfWWVhciIpKSAlPiUNCiAgcmVuYW1lKGNvdW50cnk9Q291bnRyeSkNCiNWaWV3KGRmX3RlbXApDQoNCiNkZl90ZW1wIDwtIGRhdGEuZnJhbWUoY291bnRyeT1kZl90ZW1wWywxXSxhdmc9cm93TWVhbnMoZGZfdGVtcFssLTFdKSkNCmRmX3RlbXAgPC0gZGZfdGVtcCAlPD4lIGdyb3VwX2J5KGNvdW50cnkpICU+JSBzdW1tYXJpc2UoYXZnX3RlbXAgPSBtZWFuKEF2Z19ZZWFyLG5hLnJtID0gVFJVRSklPiUgcm91bmQoMSkpDQpkZl90ZW1wDQpgYGANCg0KYGBge3J9DQojI3RlbXAgYmFyDQpkZl90ZW1wLmFsbCA8LSBkZl90ZW1wICU+JSBtZXJnZShkYXRhLmxhdGVzdC5hbGwpDQojVmlldyhkZl90ZW1wLmFsbCkNCmRmX3RlbXBfdG9wLmFsbCA8LSBkZl90ZW1wLmFsbCAlPiUgZmlsdGVyKGNvdW50cnkgJWluJSB0b3AuY291bnRyaWVzKSAlPiUNCiAgbXV0YXRlKHJhbmtpbmcgPSByYW5raW5nIC0gMSkgJT4lDQogIGFycmFuZ2UocmFua2luZykNCiNWaWV3KGRmX3RlbXBfdG9wLmFsbCkNCmdfdGVtcF90b3AgPC0gZGZfdGVtcF90b3AuYWxsICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGNvdW50cnksIHJhbmtpbmcpLCB5ID0gYXZnX3RlbXAsIGZpbGwgPSBhdmdfdGVtcCkpICsNCiAgbGFicyh0aXRsZT1wYXN0ZTAoIlRlbXBlcmF0dXJlIGluIFRvcCAgMjAgY291bnRyaWVzIiksIHN1YnRpdGxlID0gIkF2ZXJhZ2UgVGVtcGVyYXR1cmUgaW4gVG9wIDIwIGNvdW50cmllcyB3aXRoIG1vc3QgY29uZmlybWVkIGNhc2VzICjCsEMpICgyMDIwKSIpICsNCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gIiM5M0RCRkYiLCBoaWdoID0gIiNGRjc3NzEiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWw9YXZnX3RlbXAsIHk9YXZnX3RlbXApLCBzaXplPTQsIHZqdXN0PS0wLjUpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKw0KICB0aGVtZSgNCiAgICAgICAgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSdub25lJywNCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBoanVzdCA9IDAuNSksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBoanVzdCA9IDAuNSksDQogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemUgPSA5LCBhbmdsZT00NSwgaGp1c3Q9MSkpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0gIkNvdW50cnkiKSArDQogIHNjYWxlX3lfZGlzY3JldGUobmFtZSA9ICJBdmVyYWdlIFRlbXBlcmF0dXJlIikNCg0KICAgICAgICAgICAjbGFicyh0aXRsZSA9ICJUZW1wZXJhdHVyZSBpbiBUb3AgIDIwIGNvdW50cmllcyIsIHN1YnRpdGxlID0gIlRlbXBlcmF0dXJlIGluIFRvcCAyMCBjb3VudHJpZXMgd2l0aCBtb3N0IGNvbmZpcm1lZCBjYXNlcyAowrBDKSIpDQogICAgICAgICANCiNnX3RlbXBfdG9wICAgICAgICAgDQpnX3RlbXBfdG9wIA0KYGBgDQoNCmBgYHtyfQ0KI2RhdGEubGF0ZXN0LmFsbA0KbGF0LmxvbmcgPC0gcmVuYW1lKGRmX2NvbmYsICJjb3VudHJ5IiA9ICJDb3VudHJ5LlJlZ2lvbiIsICJjaXR5IiA9ICJQcm92aW5jZS5TdGF0ZSIpICU+JSANCiAgc2VsZWN0KCJjb3VudHJ5IiwgIkxhdCIsICJMb25nIikgJT4lIA0KICBtZXJnZShkZl90ZW1wLmFsbFtjKCJjb3VudHJ5IiwiY29uZmlybWVkIiwgInJlY292ZXJlZCIsICJkZWF0aHMiLCAiYXZnX3RlbXAiLCAicmFua2luZyIpXSwgYnkgPSAiY291bnRyeSIpICU+JQ0KICBkaXN0aW5jdChjb3VudHJ5LCAua2VlcF9hbGwgPSBUUlVFKSAlPiUNCiAgbXV0YXRlKHJhbmtpbmcgPSByYW5raW5nIC0gMSkgJT4lDQogIGFycmFuZ2UocmFua2luZykNCiNWaWV3KGxhdC5sb25nKQ0KYGBgDQoNCmBgYHtyfQ0KbGFiZWxfd29ybGQgPC0gbGF0LmxvbmcgDQpsYWJlbF93b3JsZCRhdmdfdGVtcCA8LSBhcy5udW1lcmljKGxhYmVsX3dvcmxkWywgbmFtZXMobGFiZWxfd29ybGQpICVpbiUgYygiYXZnX3RlbXAiKV0pDQpsYWJlbF93b3JsZCA8LSBsYWJlbF93b3JsZCAlPiUgIA0KICBtdXRhdGUodHh0PXBhc3RlMCgnPGI+JyxyYW5raW5nLCAnPC9iPicsDQogICAgICAgICAgICAgICAgICAgICc8YnIvPicsJzxiPicsY291bnRyeSwgJzwvYj4nLA0KICAgICAgICAgICAgICAgICAgICAnPGJyLz4nLCAiVGVtcGVyYXR1cmU6ICAiLGF2Z190ZW1wLCAnIMKwQycsDQogICAgICAgICAgICAgICAgICAgICc8YnIvPicsICJDb25maXJtZWQ6ICAiLCBjb25maXJtZWQsIA0KICAgICAgICAgICAgICAgICAgICAnPGJyLz4nLCAiRGVhdGhzOiAiLCBkZWF0aHMsDQogICAgICAgICAgICAgICAgICAgICc8YnIvPicsICJSZWNvdmVyZWQ6ICIsIHJlY292ZXJlZA0KICAgICAgICAgICAgICAgICAgICApKSANCg0KbGFiZWxfd29ybGQkdHh0IDwtIGxhYmVsX3dvcmxkJHR4dCAlPiUgbGFwcGx5KGh0bWx0b29sczo6SFRNTCkNCmxhYmVsX3dvcmxkIA0KDQpsYWJlbF90b3AgPC0gbGFiZWxfd29ybGQgJT4lIGZpbHRlcihyYW5raW5nIDwgMjEpDQpsYWJlbF90b3ANCmBgYA0KDQoNCmBgYHtyfQ0KIyBUZW1wZXJhdHVyZSBNYXANCndwYWwgPC0gY29sb3JOdW1lcmljKCJZbE9yUmQiLCBsYWJlbF93b3JsZCRhdmdfdGVtcCwgbiA9IDQpDQoNCnRvcEljb24gPC0gbWFrZUljb24oInN0YXIucG5nIiwNCiAgI2ljb25VcmwgPSAiaHR0cHM6Ly9zdGF0aWMudmVjdGVlenkuY29tL3N5c3RlbS9yZXNvdXJjZXMvcHJldmlld3MvMDAxLzE4OS8wNjMvbm9uXzJ4L3N0YXItcm91bmRlZC1wbmcucG5nIiwNCiAgaWNvbldpZHRoID0gMTAsIGljb25IZWlnaHQgPSAxMA0KICAjaWNvbkFuY2hvclggPSAyMCwgaWNvbkFuY2hvclkgPSAyMA0KICANCikNCg0KbGFiZWxfd29ybGQgPC0gbGFiZWxfd29ybGQgJT4lIGZpbHRlcihyYW5raW5nID4gMjApIA0KICANCm0gPC0gbGVhZmxldCh3aWR0aD0xMjAwLCBoZWlnaHQ9ODAwKSAlPiUgYWRkVGlsZXMoKSAgDQptICU8PiUgIGFkZENpcmNsZU1hcmtlcnMobGFiZWxfd29ybGQkTG9uZywgbGFiZWxfd29ybGQkTGF0LA0KICAgICAgICAgICAgICAgICAgICAgICAgIyByYWRpdXM9Mitsb2cyKHgkY29uZmlybWVkKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHJhZGl1cz0xMCwjKmxvZzIobS53b3JsZCRhdmcudGVtcCksDQogICAgICAgICAgICAgICAgICAgICAgICBzdHJva2U9RiwNCiAgICAgICAgICAgICAgICAgICAgICAgICNjb2xvcj0ncmVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gd3BhbChsYWJlbF93b3JsZCRhdmdfdGVtcCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHk9MC41LA0KICAgICAgICAgICAgICAgICAgICAgICAgI3BvcHVwPWxhYmVsLnRvcCR0eHQNCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSBsYWJlbF93b3JsZCR0eHQsDQogICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9ICJXb3JsZCINCiAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lDQogIA0KICBhZGRDaXJjbGVNYXJrZXJzKGxhYmVsX3RvcCRMb25nLCBsYWJlbF90b3AkTGF0LA0KICAgICAgICAgICAgICAgICAgICAgICAgIyByYWRpdXM9Mitsb2cyKHgkY29uZmlybWVkKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHJhZGl1cz0xMCwjKmxvZzIobS53b3JsZCRhdmcudGVtcCksDQogICAgICAgICAgICAgICAgICAgICAgICBzdHJva2U9RiwNCiAgICAgICAgICAgICAgICAgICAgICAgICNjb2xvcj0ncmVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gd3BhbChsYWJlbF90b3AkYXZnX3RlbXApLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5PTAuNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICNwb3B1cD1sYWJlbC50b3AkdHh0DQogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0gbGFiZWxfdG9wJHR4dCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gIlRvcCAyMCBDb3VudHJpZXMiDQogICAgICAgICAgICAgICAgICAgICAgICApICU+JQ0KICANCiAgYWRkTGFiZWxPbmx5TWFya2VycyhsYWJlbF90b3AkTG9uZywgbGFiZWxfdG9wJExhdCwgbGFiZWwgPSBsYWJlbF90b3AkcmFua2luZywNCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMobm9IaWRlID0gVFJVRSwgdGV4dE9ubHkgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImhlYWQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2Zmc2V0ID0gYyg1LDQpKSwNCiAgICAgICAgICAgICAgICAgICAgICBncm91cCA9ICJUb3AgMjAgQ291bnRyaWVzIikgJT4lDQogIA0KICBhZGRMZWdlbmQoImJvdHRvbXJpZ2h0IiwgcGFsID0gd3BhbCwgdmFsdWVzID0gbGFiZWxfd29ybGQkYXZnX3RlbXAsIG9wYWNpdHkgPSAxLA0KICAgICAgICAgICAgbGFiRm9ybWF0ID0gbGFiZWxGb3JtYXQoc3VmZml4ID0gIiDCsEMiKSwNCiAgICAgICAgICAgIHRpdGxlID0gIlRlbXBlcmF0dXJlIikgJT4lIA0KICANCiAgYWRkTGF5ZXJzQ29udHJvbCgNCiAgICAjYmFzZUdyb3VwcyA9IGMoIk9TTSAoZGVmYXVsdCkiLCAiVG9uZXIiLCAiVG9uZXIgTGl0ZSIpLA0KICAgIG92ZXJsYXlHcm91cHMgPSBjKCJUb3AgMjAgQ291bnRyaWVzIiwgIldvcmxkIiksDQogICAgb3B0aW9ucyA9IGxheWVyc0NvbnRyb2xPcHRpb25zKGNvbGxhcHNlZCA9IEZBTFNFKQ0KICApDQptDQpgYGANCg0KYGBge3J9DQpnZHAudG9wMjAgPC0gZGZfZ2RwMjAxOSAlPiUNCiAgc2VsZWN0KGMoInJhbmsiLCAiY291bnRyeSIsICJHRFAgKG1pbGxpb25zIG9mIFVTIGRvbGxhcnMpIikpICU+JQ0KICBtZXJnZShkYXRhLmxhdGVzdC5hbGwgJT4lIA0KICAgICAgICAgIHNlbGVjdChjb3VudHJ5LCByYW5raW5nLCBjb25maXJtZWQsIHJlY292ZXJlZCwgZGVhdGhzKSAlPiUgDQogICAgICAgICAgZmlsdGVyKGNvdW50cnkgJWluJSB0b3AuY291bnRyaWVzICYgY291bnRyeSAhPSAiV29ybGQiKSwgYnkgPSAiY291bnRyeSIpICU+JQ0KICBhcnJhbmdlKHJhbmtpbmcpICU+JSANCiAgbXV0YXRlKHJhbmtpbmcgPSByYW5raW5nIC0gMSkgDQpnZHAudG9wMjAgJTw+JSByZW5hbWUoIkdEUCIgPSAiR0RQIChtaWxsaW9ucyBvZiBVUyBkb2xsYXJzKSIpDQpnZHAudG9wMjANCg0KZyA8LSBnZ3Bsb3QoZ2RwLnRvcDIwLCBhZXMoeCA9IEdEUCwgeSA9IHJlb3JkZXIoY291bnRyeSwgLXJhbmtpbmcpKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShzdGF0ID0gImlkZW50aXR5IiwgYWVzKGZpbGwgPSBHRFApKSsgDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoIkdEUCIsIGxvdyA9ICIjRkY0MDM4IiwgaGlnaCA9ICIjNTBFOTUyIikgKyANCiAgbGFicyh0aXRsZT1wYXN0ZTAoIkdEUCAgb2YgVG9wIDIwIENvdW50cmllcyBpbiAyMDE5IChtaWxsaW9ucyBvZiBVUyBkb2xsYXJzKSIpKSArDQogIGdlb21fdGV4dChhZXMobGFiZWw9R0RQLCB4ID0gR0RQKSwgc2l6ZT0zLjUsIGhqdXN0PS0wLjIpICsNCiAgeGxhYigiR0RQIChtaWxsaW9ucyBvZiBVUyBkb2xsYXJzKSIpICsNCiAgeWxhYigiIikgKw0KICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKQ0KZw0KDQpnbHkudG9wLmdkcCA8LSBnZ3Bsb3RseShnKQ0KZ2x5LnRvcC5nZHANCmBgYA0KDQpgYGB7cn0NCiMgUG9ybmh1Yg0KZGZfcG9ybmh1YiA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBwb3JuaHViIikpDQpkZl9wb3JuaHViIDwtIGFzLmRhdGEuZnJhbWUoZGZfcG9ybmh1YikNCmRmX3Bvcm5odWINCmBgYA0KDQoNCmBgYHtyfQ0KIyBTYXJzDQpkZl9zYXJzIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIHNhcnNfMjAwMyIpKQ0KZGZfc2FycyA8LSBhcy5kYXRhLmZyYW1lKGRmX3NhcnMpDQojVmlldyhkZl9zYXJzKQ0KDQpkYXRlcy5zIDwtIGRmX3NhcnNbLDFdJT4lIG1keSgpDQpyYW5nZShkYXRlcy5zKQ0KbWluLmRhdGUucyA8LSBtaW4oZGF0ZXMucykNCm1heC5kYXRlLnMgPC0gbWF4KGRhdGVzLnMpDQptaW4uZGF0ZS50eHQucyA8LSBtaW4uZGF0ZS5zICU+JSBmb3JtYXQoJyVkICViICVZJykNCm1heC5kYXRlLnR4dC5zIDwtIG1heC5kYXRlLnMgJT4lIGZvcm1hdCgnJWQgJWIgJVknKQ0KZGF5MS5zYXJzIDwtIG1pbi5kYXRlLnMNCmBgYA0KDQpgYGB7cn0NCiMgY2xlYW4gZGF0YSBTYXJzIA0KZGF0YS5zYXJzIDwtIGRmX3NhcnMgJT4lIHJlbmFtZShjKCJkYXRlIiA9ICJEYXRlIiwgImNvbmZpcm1lZCIgPSAiQ3VtdWxhdGl2ZV9udW1iZXIiICAsImRlYXRocyIgPSAiTnVtYmVyX2RlYXRocyIsICJyZWNvdmVyZWQiID0gIk51bWJlcl9yZWNvdmVyZWQiKSkgJT4lDQogIG11dGF0ZShkYXRlID0gZGF0ZSAlPiUgbWR5KCkpICU+JQ0KICBncm91cF9ieShjb3VudHJ5LCBkYXRlKSAlPiUgYXMuZGF0YS5mcmFtZSgpIA0KDQojIEFkZCBXb3JsZCdzIFNhcnMgY2FzZXMgDQp3b3JsZC5zYXJzIDwtIGRhdGEuc2FycyAlPiUgZ3JvdXBfYnkoZGF0ZSkgJT4lIA0KICBzdW1tYXJpc2UoY291bnRyeT0nV29ybGQnLA0KICAgICAgICAgICAgY29uZmlybWVkID0gc3VtKGNvbmZpcm1lZCwgbmEucm09VCksDQogICAgICAgICAgICBkZWF0aHMgPSBzdW0oZGVhdGhzLCBuYS5ybT1UKSwNCiAgICAgICAgICAgIHJlY292ZXJlZCA9IHN1bShyZWNvdmVyZWQsIG5hLnJtPVQpKQ0KDQpkYXRhLnNhcnMgJTw+JSByYmluZCh3b3JsZC5zYXJzKQ0KZGF0YS5zYXJzICU8PiUgbXV0YXRlKGN1cnJlbnQuY29uZmlybWVkID0gY29uZmlybWVkIC0gZGVhdGhzIC0gcmVjb3ZlcmVkKQ0KI1ZpZXcod29ybGQuc2FycykgDQpkYXRhLnNhcnMNCmBgYA0KDQoNCmBgYHtyfQ0KI3JhdGUNCmRhdGEuc2FycyAlPD4lIGFycmFuZ2UoY291bnRyeSwgZGF0ZSkNCm4gPC0gbnJvdyhkYXRhLnNhcnMpDQpkYXkxLnNhcnMgPC0gbWluKGRhdGEuc2FycyRkYXRlKQ0KZGF0YS5zYXJzICU8PiUgbXV0YXRlKG5ldy5jb25maXJtZWQgPSBpZmVsc2UoZGF0ZSA9PSBkYXkxLnNhcnMsIE5BLCBjb25maXJtZWQgLSBsYWcoY29uZmlybWVkLCBuPTEpKSwNCiAgICAgICAgICAgICAgICAgbmV3LmRlYXRocyA9IGlmZWxzZShkYXRlID09IGRheTEuc2FycywgTkEsIGRlYXRocyAtIGxhZyhkZWF0aHMsIG49MSkpLA0KICAgICAgICAgICAgICAgICBuZXcucmVjb3ZlcmVkID0gaWZlbHNlKGRhdGUgPT0gZGF5MS5zYXJzLCBOQSwgcmVjb3ZlcmVkIC0gbGFnKHJlY292ZXJlZCwgbj0xKSkpDQpkYXRhLnNhcnMgJTw+JSBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShuZXcuY29uZmlybWVkIDwgMCwgMCwgbmV3LmNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgIG5ldy5kZWF0aHMgPSBpZmVsc2UobmV3LmRlYXRocyA8IDAsIDAsIG5ldy5kZWF0aHMpLA0KICAgICAgICAgICAgICAgICBuZXcucmVjb3ZlcmVkID0gaWZlbHNlKG5ldy5yZWNvdmVyZWQgPCAwLCAwLCBuZXcucmVjb3ZlcmVkKSkNCiMjIGRlYXRoIHJhdGUgYmFzZWQgb24gdG90YWwgZGVhdGhzIGFuZCByZWNvdmVyZWQgY2FzZXMNCmRhdGEuc2FycyAlPD4lIG11dGF0ZShyYXRlLnVwcGVyID0gKDEwMCAqIGRlYXRocyAvIChkZWF0aHMgKyByZWNvdmVyZWQpKSAlPiUgcm91bmQoMSksDQogICAgICAgICAgICAgICAgIHJhdGUudXBwZXIgPSBpZmVsc2UoaXMubmFuKHJhdGUudXBwZXIpLCAwLCByYXRlLnVwcGVyKSkNCg0KIyMgbG93ZXIgYm91bmQ6IGRlYXRoIHJhdGUgYmFzZWQgb24gdG90YWwgY29uZmlybWVkIGNhc2VzDQpkYXRhLnNhcnMgJTw+JSBtdXRhdGUocmF0ZS5sb3dlciA9ICgxMDAgKiBkZWF0aHMgLyBjb25maXJtZWQpICU+JSByb3VuZCgxKSwNCiAgICAgICAgICAgICAgICAgcmF0ZS5sb3dlciA9IGlmZWxzZShpcy5uYW4ocmF0ZS5sb3dlciksIDAsIHJhdGUubG93ZXIpKQ0KDQojIyBkZWF0aCByYXRlIGJhc2VkIG9uIHRoZSBudW1iZXIgb2YgZGVhdGgvcmVjb3ZlcmVkIG9uIGV2ZXJ5IHNpbmdsZSBkYXkNCmRhdGEuc2FycyAlPD4lIG11dGF0ZShyYXRlLmRhaWx5ID0gKDEwMCAqIG5ldy5kZWF0aHMgLyAobmV3LmRlYXRocyArIG5ldy5yZWNvdmVyZWQpKSAlPiUgcm91bmQoMSksDQogICAgICAgICAgICAgICAgIHJhdGUuZGFpbHkgPSBpZmVsc2UoaXMubmFuKHJhdGUuZGFpbHkpLCAwLCByYXRlLmRhaWx5KSkNCg0KI1ZpZXcoZGF0YS5zYXJzKQ0KYGBgDQoNCmBgYHtyfQ0KIyMgY29udmVydCBmcm9tIHdpZGUgdG8gbG9uZyBmb3JtYXQNCmRhdGEuc2Fycy5sb25nIDwtIGRhdGEuc2FycyAlPiUNCiAgc2VsZWN0KGMoY291bnRyeSwgZGF0ZSwgY29uZmlybWVkLCBjdXJyZW50LmNvbmZpcm1lZCwgcmVjb3ZlcmVkLCBkZWF0aHMpKSAlPiUNCiAgZ2F0aGVyKGtleT10eXBlLCB2YWx1ZT1jb3VudCwgLWMoY291bnRyeSwgZGF0ZSkpDQojIyBzZXQgZmFjdG9yIGxldmVscyB0byBzaG93IHRoZW0gaW4gYSBkZXNpcmFibGUgb3JkZXINCmRhdGEuc2Fycy5sb25nICU8PiUgbXV0YXRlKHR5cGU9cmVjb2RlX2ZhY3Rvcih0eXBlLCBjb25maXJtZWQ9J1RvdGFsIENvbmZpcm1lZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnQuY29uZmlybWVkPSdDdXJyZW50IENvbmZpcm1lZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY292ZXJlZD0nUmVjb3ZlcmVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVhdGhzPSdEZWF0aHMnKSkNCiNWaWV3KGRhdGEuc2Fycy5sb25nKQ0KDQojIFdvcmxkIHNhcnMnIGxvbmcgZGF0YSANCndvcmxkLnNhcnMubG9uZyA8LSBkYXRhLnNhcnMubG9uZyAlPiUNCiAgZmlsdGVyKGNvdW50cnkgPT0gIldvcmxkIikNCiNWaWV3KHdvcmxkLnNhcnMubG9uZykNCg0KZyA8LSBnZ3Bsb3Qod29ybGQuc2Fycy5sb25nLCBhZXMoZGF0ZSwgY291bnQsIGNvbG9yID0gdHlwZSkpICsNCiAgZ2VvbV9saW5lKCkrDQogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIENhc2VzIFdvcmxkd2lkZTogU0FScyIpKw0KICB4bGFiKCIiKSsNCiAgeWxhYigiIikNCmcNCg0KZ2x5LmcgPC0gZ2dwbG90bHkoZykNCmdseS5nDQpnbHkucGxvdF93b3JsZC5saW5lDQpgYGANCg0KYGBge3J9DQpkZl9zYXJzX2xhc3RkYXRlIDwtIGRhdGEuc2FycyAlPiUNCiAgZmlsdGVyKGRhdGUgPT0gbWF4LmRhdGUucykNCg0KZGZfc2Fyc19sYXN0ZGF0ZQ0KYGBgDQoNCg0KYGBge3J9DQojIyBDdXJyZW50IENvbmZpcm1lZCBDYXNlcw0KZGF0YS5zYXJzLndvcmxkIDwtIGRhdGEuc2FycyAlPiUgZmlsdGVyKGNvdW50cnk9PSdXb3JsZCcpDQojVmlldyhkYXRhLnNhcnMud29ybGQpDQpuIDwtIG5yb3coZGF0YS5zYXJzLndvcmxkKQ0KI1ZpZXcoZGF0YS5zYXJzLndvcmxkKQ0KcGxvdF9zYXJzLmN1cnJjb25mIDwtIGdncGxvdChkYXRhLnNhcnMud29ybGQsIGFlcyh4PWRhdGUsIHk9Y3VycmVudC5jb25maXJtZWQpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdDdXJyZW50IENvbmZpcm1lZCBDYXNlcycpICsNCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkNCnBsb3Rfc2Fycy5uZXdjb25mIDwtIGdncGxvdChkYXRhLnNhcnMud29ybGQsIGFlcyh4PWRhdGUsIHk9bmV3LmNvbmZpcm1lZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J0RhaWx5IE5ldyBDb25maXJtZWQgQ2FzZXMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQojIyBzaG93IHR3byBwbG90cyBzaWRlIGJ5IHNpZGUNCmdyaWQuYXJyYW5nZShwbG90X3NhcnMuY3VycmNvbmYsIHBsb3Rfc2Fycy5uZXdjb25mLCBuY29sPTIpDQpgYGANCg0KYGBge3J9DQojIyBhIHNjYXR0ZXIgcGxvdCB3aXRoIGEgc21vb3RoZWQgbGluZSBhbmQgdmVydGljYWwgeC1heGlzIGxhYmVscw0KcGxvdF9zYXJzLmFjY2RlYXRocyA8LSBnZ3Bsb3QoZGF0YS5zYXJzLndvcmxkLCBhZXMoeD1kYXRlLCB5PWRlYXRocykpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J0FjY3VtdWxhdGl2ZSBEZWF0aHMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQpwbG90X3NhcnMuYWNjcmVjb3YgPC0gZ2dwbG90KGRhdGEuc2Fycy53b3JsZCwgYWVzKHg9ZGF0ZSwgeT1yZWNvdmVyZWQpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdBY2N1bXVsYXRpdmUgUmVjb3ZlcmVkIENhc2VzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdF9zYXJzLm5ld2RlYXRocyA8LSBnZ3Bsb3QoZGF0YS5zYXJzLndvcmxkLCBhZXMoeD1kYXRlLCB5PW5ldy5kZWF0aHMpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdOZXcgRGVhdGhzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdF9zYXJzLm5ld3JlY292IDwtIGdncGxvdChkYXRhLnNhcnMud29ybGQsIGFlcyh4PWRhdGUsIHk9bmV3LnJlY292ZXJlZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J05ldyBSZWNvdmVyZWQgQ2FzZXMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQojIyBzaG93IGZvdXIgcGxvdHMgdG9nZXRoZXIsIHdpdGggMiBwbG90cyBpbiBlYWNoIHJvdw0KZ3JpZC5hcnJhbmdlKHBsb3Rfc2Fycy5hY2NkZWF0aHMsIHBsb3Rfc2Fycy5hY2NyZWNvdiwgcGxvdF9zYXJzLm5ld2RlYXRocywgcGxvdF9zYXJzLm5ld3JlY292LCBucm93PTIpDQpgYGANCg0KDQpgYGB7cn0NCiNUb3AgMjAgd2l0aCBnZHANCmRhdGEubG9uZ0dEUCA8LSBkZl9nZHAyMDE5ICU+JSBnYXRoZXIoa2V5PXllYXIsIHZhbHVlPUdEUCwgLWMoY291bnRyeSkpDQpkYXRhLnRvcCA8LSBkYXRhLmxhdGVzdCAlPiUgZmlsdGVyKCFjb3VudHJ5ICVpbiUgYygnV29ybGQnLCAnT3RoZXJzJykpDQpkYXRhLnRvcCA8LSBoZWFkKGRhdGEudG9wLDIwKQ0KI1ZpZXcoZGF0YS5sYXRlc3QpDQpkYXRhLmdkcCA8LSBmaWx0ZXIoZGF0YS5sb25nR0RQLHllYXI9PScyMDIwJykNCmRmX3NhcnNfbGFzdGRhdGVfY29uZmlybWVkIDwtIGRmX3NhcnNfbGFzdGRhdGUgJT4lDQogIHNlbGVjdCgiY291bnRyeSIsICJjb25maXJtZWQiKSAlPiUNCiAgcmVuYW1lKHNhcnMgPSAiY29uZmlybWVkIikNCiNWaWV3KGRmX3NhcnNfbGFzdGRhdGVfY29uZmlybWVkKQ0KI21lcmdlDQptZXJnY291bnRyeSA9IGZ1bmN0aW9uKGRhdGExLGRhdGEyKXsNCiAgZGF0YSA8LSBtZXJnZSh4ID0gZGF0YTEsIHkgPSBkYXRhMiwgYnkgPSAiY291bnRyeSIsIGFsbC54ID0gVFJVRSkgDQogIHJldHVybihkYXRhKQ0KfQ0KZGF0YS50b3Aud29ybGQgPC0gbWVyZ2UoeCA9IGRhdGEudG9wLCB5ID0gZGZfZ2RwMjAxOSwgYnkgPSAiY291bnRyeSIsIGFsbC54ID0gVFJVRSkgJT4lIA0KICBzZWxlY3QoLWMoY29kZSxyYW5rLG5ldy5jb25maXJtZWQsbmV3LmRlYXRocyxjdXJyZW50LmNvbmZpcm1lZCxwb3B1bGF0aW9uKSkgJT4lIA0KICByZW5hbWUoR0RQPSJHRFAgKG1pbGxpb25zIG9mIFVTIGRvbGxhcnMpIikNCg0KZGF0YS50b3Aud29ybGQgPC0gbWVyZ2UoeCA9IGRhdGEudG9wLndvcmxkLCB5ID0gZGZfaGVhbHQsIGJ5ID0gImNvdW50cnkiLCBhbGwueCA9IFRSVUUpICU+JQ0KICByZW5hbWUoaGVhbHRoY2FyZT0iaGVhbHRoQ2FyZUluZGV4IikNCiNkYXRhLnRvcC53b3JsZCA8LSBtZXJnY291bnRyeShkYXRhLnRvcC53b3JsZCwgZGZfdGVtcCkNCg0KZGF0YS50b3Aud29ybGQgPC0gbWVyZ2UoeCA9IGRhdGEudG9wLndvcmxkLCB5ID0gZGZfcG9ybmh1YiwgYnkgPSAiY291bnRyeSIsIGFsbC54ID0gVFJVRSkgJT4lDQogIHJlbmFtZShQb3JuaHViID0gIlBvcm5odWJJbmRleCglKSIpDQoNCmRhdGEudG9wLndvcmxkIDwtIG1lcmdlKHggPSBkYXRhLnRvcC53b3JsZCwgeSA9IGRmX3NhcnNfbGFzdGRhdGVfY29uZmlybWVkLCBieSA9ICJjb3VudHJ5IiwgYWxsLnggPSBUUlVFKSANCg0KDQpkYXRhLnRvcC53b3JsZCA8LSBtZXJnY291bnRyeShkYXRhLnRvcC53b3JsZCwgZGZfdGVtcCkNCmluZGV4IDwtIGlzLm5hKGRhdGEudG9wLndvcmxkKQ0KZGF0YS50b3Aud29ybGRbaW5kZXhdIDwtIDANCmRhdGEudG9wLndvcmxkDQpWaWV3KGRhdGEudG9wLndvcmxkKQ0KDQoNCm5vcm1hbGl6ZSA9IGZ1bmN0aW9uKGRhdGEpew0KICAjcmV0dXJuICgoZGF0YSAtIG1pbihkYXRhLG5hLnJtID0gVFJVRSkpLyhtYXgoZGF0YSxuYS5ybSA9IFRSVUUpIC0gbWluKGRhdGEsbmEucm0gPSBUUlVFKSkpDQogIHogPC0gc2NhbGUoZGF0YSk7DQogIHRhbmgoei8yKQ0KfQ0KDQpub3JtX2RhdGEgPSBhcy5kYXRhLmZyYW1lKGFwcGx5KGRhdGEudG9wLndvcmxkWywyOjEzXSwyLG5vcm1hbGl6ZSkpDQpjb3JyX2RhdGEgPC0gbm9ybV9kYXRhDQpub3JtX2RhdGEkY291bnRyeSA8LSBjKCJBcmdlbnRpbmEiLCJCYW5nbGFkZXNoIiwiQnJhemlsIiwiQ2hpbGUiLCJDb2xvbWJpYSIsIkZyYW5jZSIsIkdlcm1hbnkiLCJJbmRpYSIsIklyYW4iLCJJdGFseSIsIk1leGljbyIsIlBha2lzdGFuIiwiUGVydSIsIlJ1c3NpYSIsInNhdWRpIEFyYWJpYSIsIlNvdXRoIEFmcmljYSIsIlNwYWluIiwiVHVya2V5IiwiVW5pdGVkIEtpbmdkb20iLCJVUyIpDQpub3JtX2RhdGEgPC0gbm9ybV9kYXRhWyxjKG5jb2wobm9ybV9kYXRhKSwxOihuY29sKG5vcm1fZGF0YSktMSkpXQ0Kcm93bmFtZXMobm9ybV9kYXRhKSA8LSBub3JtX2RhdGFbLDFdDQpub3JtX2RhdGFbLDFdIDwtIE5VTEwNCg0KI2hlYXRtYXAoYXMubWF0cml4KG5vcm1fZGF0YVssIC0xXSksc2NhbGU9ImNvbHVtbiIsY29sPSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOCwgIkJsdWVzIikpKDI1KSkNCiNsZWdlbmQoeD0iYm90dG9tcmlnaHQiLCBsZWdlbmQ9YygiLTEiLCAiMCIsICIxIiksIA0KIyAgICAgZmlsbD1jb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOCwgIkJsdWVzIikpKDMpKQ0KDQojIGluc3RhbGwucGFja2FnZXMoImdwbG90cyIpDQpsaWJyYXJ5KCJncGxvdHMiKQ0KbGlicmFyeSgic3RyaW5nciIpDQpub3JtX2RhdGFfcGxvdCA8LSBzZWxlY3Qobm9ybV9kYXRhLCJjb25maXJtLnJhdGUiLCJkZWF0aC5yYXRlIiwicmVjb3Zlci5yYXRlIiwiaGVhbHRoY2FyZSIsIlBvcm5odWIiLCJHRFAiLCJhdmdfdGVtcCIsICJzYXJzIikNCm5vcm1fZGF0YV9wbG90DQp3b3JsZF9jbHVzdCA8LSBhcy5tYXRyaXgobm9ybV9kYXRhX3Bsb3QpDQpoZWF0bWFwLmNsdXN0IDwtIGhlYXRtYXAuMihhcy5tYXRyaXgobm9ybV9kYXRhX3Bsb3QpLA0KICAgICAgICAgICAgICAgICAgICBzY2FsZT0ibm9uZSIsIA0KICAgICAgICAgICAgICAgICAgICBjb2wgPSBjb2xvclJhbXBQYWxldHRlKGMoIiM2RDlFQzEiLCJ3aGl0ZSIsIiNFNDY3MjYiKSkobiA9IDIwMCksDQogICAgICAgICAgICAgICAgICAgIG1hcmdpbnM9YygxMCw2KSx0cmFjZT0iY29sdW1uIikNCiNnbHkuaGVhdG1hcDIgPC0gcGxvdGx5X2J1aWxkKGhlYXRtYXAuY2x1c3QpDQoNCg0Kbm9ybV9kYXRhMiA9IGFzLmRhdGEuZnJhbWUoYXBwbHkoZGF0YS50b3Aud29ybGRbLDI6MTNdLDIsbm9ybWFsaXplKSkNCm5vcm1fZGF0YTIkY291bnRyeSA8LSBjKCJBcmdlbnRpbmEiLCJCYW5nbGFkZXNoIiwiQnJhemlsIiwiQ2hpbGUiLCJDb2xvbWJpYSIsIkZyYW5jZSIsIkdlcm1hbnkiLCJJbmRpYSIsIklyYW4iLCJJdGFseSIsIk1leGljbyIsIlBha2lzdGFuIiwiUGVydSIsIlJ1c3NpYSIsInNhdWRpIEFyYWJpYSIsIlNvdXRoIEFmcmljYSIsIlNwYWluIiwiVHVya2V5IiwiVW5pdGVkIEtpbmdkb20iLCJVUyIpDQojVmlldyhub3JtX2RhdGEyKQ0Kbm9ybV9kYXRhX3Bsb3QyIDwtIHNlbGVjdChub3JtX2RhdGEyLCJjb3VudHJ5IiwiY29uZmlybS5yYXRlIiwiZGVhdGgucmF0ZSIsInJlY292ZXIucmF0ZSIsImhlYWx0aGNhcmUiLCJQb3JuaHViIiwiR0RQIiwiYXZnX3RlbXAiLCAic2FycyIpDQojVmlldyhub3JtX2RhdGFfcGxvdDIpDQpub3JtX2RhdGFfcGxvdDIgJTw+JSBnYXRoZXIoa2V5PXR5cGUsIHZhbHVlPWNvdW50LCAtYyhjb3VudHJ5KSkNCmxldmVsX29yZGVyIDwtIGZhY3Rvcihub3JtX2RhdGFfcGxvdDIkdHlwZSwNCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbCA9Yygic2FycyIsIlBvcm5odWIiLCJHRFAiLCJhdmdfdGVtcCIsImhlYWx0aGNhcmUiLCJyZWNvdmVyLnJhdGUiLCJkZWF0aC5yYXRlIiwiY29uZmlybS5yYXRlIikpDQpWaWV3KGxldmVsX29yZGVyKQ0KZ2dwbG90KGRhdGEgPSBub3JtX2RhdGFfcGxvdDIsIGFlcyh4PWNvdW50cnksIHk9bGV2ZWxfb3JkZXIsIGZpbGw9Y291bnQpKSArIA0KICBnZW9tX3RpbGUoKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gInBpbmsiLCBoaWdoID0gImJsdWUiKSArDQogIHhsYWIoIiIpICsNCiAgeWxhYigiIikgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCx2anVzdCA9IDEpKSsNCiAgdGhlbWUoDQogICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICNsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKQ0KDQpgYGANCg0KYGBge3J9DQojY29ycmVsYXRpb24NCmNvcnJfZGF0YSAlPD4lIHNlbGVjdChjKEdEUCxjb25maXJtLnJhdGUsZGVhdGgucmF0ZSxyZWNvdmVyLnJhdGUsaGVhbHRoY2FyZSxhdmdfdGVtcCxQb3JuaHViLCBzYXJzKSkNCmhlYWQoY29ycl9kYXRhKQ0KY29yKGNvcnJfZGF0YSkNCnBsb3Rjb3JyIDwtIGdnY29ycnBsb3QoY29yKGNvcnJfZGF0YSksaGMub3JkZXIgPSBUUlVFLA0KICAgICAgICAgICBvdXRsaW5lLmNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgICAgY29sb3JzID0gYygiIzZEOUVDMSIsIndoaXRlIiwiI0U0NjcyNiIpLA0KICAgICAgICAgICBsYWIgPSBUUlVFKQ0KDQpwbG90Y29ycg0KYGBgDQoNCmBgYHtyfQ0KIyMgRGF0YSBpbiBVUw0KDQpkZl91cyA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBjb3ZpZHVzIikpDQpkZl91cyA8LSBhcy5kYXRhLmZyYW1lKGRmX3VzKSANCmRmX3VzIDwtIHNlbGVjdChkZl91cywgZGF0ZSwgc3RhdGUsIGNhc2VzLCBkZWF0aHMpDQoNCmRmX3VzX3BvcCA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBkYXRhX3BvcHVsYXRpb24iKSkgDQpkZl91c19wb3AgPC0gYXMuZGF0YS5mcmFtZShkZl91c19wb3ApDQoNCmRmX3VzX2dlbmRlciA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBkYXRhX2dlbmRlciIpKSANCmRmX3VzX2dlbmRlciA8LSBhcy5kYXRhLmZyYW1lKGRmX3VzX2dlbmRlcikNCg0KZGZfdXNfZXRobmljIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGRhdGFfZXRobmljIikpIA0KZGZfdXNfZXRobmljIDwtIGFzLmRhdGEuZnJhbWUoZGZfdXNfZXRobmljKQ0KDQpkZl91c19sb2NrZG93biA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBkYXRhX2xvY2tkb3duIikpIA0KZGZfdXNfbG9ja2Rvd24gPC0gYXMuZGF0YS5mcmFtZShkZl91c19sb2NrZG93bikNCg0KZGZfdXNfaGVhbHRoIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGRhdGFfaGVhbHRoIikpIA0KZGZfdXNfaGVhbHRoIDwtIGFzLmRhdGEuZnJhbWUoZGZfdXNfaGVhbHRoKQ0KDQpkZl91c190ZXN0aW5nIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGRhdGFfdGVzdGluZyIpKSANCmRmX3VzX3Rlc3RpbmcgPC0gYXMuZGF0YS5mcmFtZShkZl91c190ZXN0aW5nKQ0KDQpgYGANCg0KYGBge3J9DQpkZl91cyA8LSBkZl91cyAgJT4lDQogIG11dGF0ZShkYXRlID0gZGF0ZSAlPiUgbWR5KCkpICU+JQ0KICByZW5hbWUoImNvbmZpcm1lZCIgPSAiY2FzZXMiKQ0KI2RhdGEudXMNCmRhdGVzLnVzIDwtIGRmX3VzWywxXQ0KcmFuZ2UoZGF0ZXMudXMpDQptaW4uZGF0ZS51cyA8LSBtaW4oZGF0ZXMudXMpDQptYXguZGF0ZS51cyA8LSBtYXgoZGF0ZXMudXMpDQptaW4uZGF0ZS50eHQudXMgPC0gbWluLmRhdGUudXMgJT4lIGZvcm1hdCgnJWQgJWIgJVknKQ0KbWF4LmRhdGUudHh0LnVzIDwtIG1heC5kYXRlLnVzICU+JSBmb3JtYXQoJyVkICViICVZJykNCmRheTEudXMgPC0gbWluKGRmX3VzJGRhdGUpDQoNCmRhdGEudXMudG90YWwgPC0gZGZfdXMgJT4lIGdyb3VwX2J5KGRhdGUpICU+JQ0KICBzdW1tYXJpc2Uoc3RhdGU9J1VTJywNCiAgICAgICAgICAgIGNvbmZpcm1lZCA9IHN1bShjb25maXJtZWQsIG5hLnJtPVQpLA0KICAgICAgICAgICAgZGVhdGhzID0gc3VtKGRlYXRocywgbmEucm09VCkpDQojVmlldyhkYXRhLnVzLnRvdGFsKQ0KDQpkYXRhLnVzIDwtIGRmX3VzDQpkYXRhLnVzICU8PiUgcmJpbmQoZGF0YS51cy50b3RhbCkNClZpZXcoZGF0YS51cykNCg0KZGF0YS51cy5sb25nIDwtIGRhdGEudXMgJT4lIA0KICBnYXRoZXIoa2V5ID0gdHlwZSwgdmFsdWUgPSBjb3VudCwgLWMoZGF0ZSwgc3RhdGUpKSANClZpZXcoZGF0YS51cy5sb25nKQ0KDQp1cy50b3RhbCA8LSBkYXRhLnVzLnRvdGFsICU+JQ0KICBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShkYXRlID09IGRheTEsIDAsIGNvbmZpcm1lZCAtIGxhZyhjb25maXJtZWQsIG49MSkpLA0KICAgICAgICAgICAgICAgIG5ldy5kZWF0aHMgPSBpZmVsc2UoZGF0ZSA9PSBkYXkxLCAwLCBkZWF0aHMgLSBsYWcoZGVhdGhzLCBuPTEpKSkNCg0KdXMudG90YWwgJTw+JSBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShuZXcuY29uZmlybWVkIDwgMCwgMCwgbmV3LmNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgIG5ldy5kZWF0aHMgPSBpZmVsc2UobmV3LmRlYXRocyA8IDAsIDAsIG5ldy5kZWF0aHMpKQ0KdXMudG90YWwNCg0KbW9zdF91cyA8LSB1cy50b3RhbCAlPiUgZmlsdGVyKGRhdGUgPT0gbWF4LmRhdGUudXMpDQoNCnVzLnRvdGFsLmxvbmcgPC0gdXMudG90YWwgJT4lIA0KICBnYXRoZXIoa2V5ID0gdHlwZSwgdmFsdWUgPSBjb3VudCwgLWMoZGF0ZSwgc3RhdGUpKQ0KDQojVmlldyh1cy50b3RhbC5sb25nKQ0KYGBgDQoNCg0KYGBge3J9DQpwbG90X3VzLmNhc2VzIDwtIGRhdGEudXMubG9uZyAlPiUgZmlsdGVyKHN0YXRlID09ICJVUyIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gY291bnQpKSArDQogIGdlb21fYXJlYShhZXMoZmlsbD10eXBlKSwgYWxwaGE9MC41KSArDQojICBsYWJzKHRpdGxlID0gcGFzdGUwKCJDdW11bGF0aXZlIGNhc2VzIGluIFVTIDogIiwgbWluLmRhdGUudHh0LnVzLCAnLScsIG1heC5kYXRlLnR4dC51cywgIiAoU3RhY2ssIExvZyBTY2FsZSkiKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9J2xvZzEwJykgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygncmVkJywgJ2JsYWNrJykpKw0KICB5bGFiKCIiKSArDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04KSkNCiNWaWV3KHVzLnRvdGFsLmxvbmcgKQ0KcGxvdF91cy5uZXdjb25mIDwtIHVzLnRvdGFsLmxvbmcgJT4lDQogIGZpbHRlcih0eXBlICVpbiUgYygibmV3LmNvbmZpcm1lZCIsIm5ldy5kZWF0aHMiKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSBjb3VudCwgY29sb3IgPSB0eXBlKSkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgI2xhYnModGl0bGUgPSBwYXN0ZTAoIkRhaWx5IGNvbmZpcm1lZCBjYXNlcyBpbiBVUyA6ICIsIG1pbi5kYXRlLnR4dC51cywgJy0nLCBtYXguZGF0ZS50eHQudXMpKSArDQogIHhsYWIoIkRhdGUiKSArDQogIHlsYWIoIkNvbmZpcm1lZCBjYXNlcyIpDQoNCmdseS5wbG90X3VzLmNhc2VzIDwtIGdncGxvdGx5KHBsb3RfdXMuY2FzZXMpDQpnbHkucGxvdF91cy5jYXNlcyA8LSBnbHkucGxvdF91cy5jYXNlcyAlPiUgDQogIGxheW91dCh0aXRsZSA9IHBhc3RlMCgiPGI+Q3VtdWxhdGl2ZSBjYXNlcyBpbiBVUyA6ICIsIG1pbi5kYXRlLnR4dC51cywgJy0nLCBtYXguZGF0ZS50eHQudXMsICIgKFN0YWNrLCBMb2cgU2NhbGUpIiksIA0KICAgICAgICAgZm9udD1saXN0KHNpemUgPSAxMCkpDQpnbHkucGxvdF91cy5uZXdjb25mIDwtIGdncGxvdGx5KHBsb3RfdXMubmV3Y29uZikgJT4lIA0KICBsYXlvdXQodGl0bGUgPSBwYXN0ZTAoIjxiPkRhaWx5IGNvbmZpcm1lZCBjYXNlcyBpbiBVUyA6ICIsIG1pbi5kYXRlLnR4dC51cywgJy0nLCBtYXguZGF0ZS50eHQudXMpLCANCiAgICAgICAgIGZvbnQ9bGlzdChzaXplID0gMTApKQ0KDQpnbHkucGxvdF91cy5jYXNlcyAgDQpnbHkucGxvdF91cy5uZXdjb25mDQoNCmBgYA0KDQpgYGB7cn0NCmRhdGEudXMgJTw+JSBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCBjb25maXJtZWQgLSBsYWcoY29uZmlybWVkLCBuPTEpKSwNCiAgICAgICAgICAgICAgICAgbmV3LmRlYXRocyA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCBkZWF0aHMgLSBsYWcoZGVhdGhzLCBuPTEpKSkNCg0KZGF0YS51cyAlPD4lIG11dGF0ZShuZXcuY29uZmlybWVkID0gaWZlbHNlKG5ldy5jb25maXJtZWQgPCAwLCAwLCBuZXcuY29uZmlybWVkKSwNCiAgICAgICAgICAgICAgICAgbmV3LmRlYXRocyA9IGlmZWxzZShuZXcuZGVhdGhzIDwgMCwgMCwgbmV3LmRlYXRocykpDQpWaWV3KGRhdGEudXMpDQoNCiNkYXRhLnVzLmRhaWx5IDwtIGRhdGEudXMgJT4lIGZpbHRlcihzdGF0ZSA9PSAiVVMiKQ0KI1ZpZXcoZGF0YS51cy5kYWlseSkNCg0KZGF0YS51cy5wb3AgPC0gZGZfdXNfcG9wICU+JSBzZWxlY3QoU3RhdGUsIFBvcHVsYXRpb24pICU+JQ0KICByZW5hbWUoInN0YXRlIiA9ICJTdGF0ZSIpIA0KI2RhdGEudXMucG9wDQoNCmRhdGEudXMuZ2VuZGVyIDwtIGRmX3VzX2dlbmRlciAlPiUgc2VsZWN0KFN0YXRlLCBNYWxlLCBGZW1hbGUpICU+JQ0KICByZW5hbWUoInN0YXRlIiA9ICJTdGF0ZSIpIA0KZGF0YS51cy5nZW5kZXINCg0KZGF0YS51cy5sYXRlc3QgPC0gZGF0YS51cyAlPiUNCiAgZmlsdGVyKGRhdGUgPT0gbWF4LmRhdGUudXMpICU+JSANCiAgbWVyZ2UoZGF0YS51cy5wb3AsIGJ5ID0gInN0YXRlIiwgYWxsLnggPSBUKSAlPiUNCiAgbWVyZ2UoZGF0YS51cy5nZW5kZXIsIGJ5ID0gInN0YXRlIiwgYWxsLnggPSBUKQ0KI1ZpZXcoZGF0YS51cy5sYXRlc3QpDQoNCmRhdGEudXMubGF0ZXN0JFBvcHVsYXRpb25bZGF0YS51cy5sYXRlc3Qkc3RhdGUgPT0gIlVTIl0gPC0gc3VtKGRhdGEudXMucG9wJFBvcHVsYXRpb24pDQpkYXRhLnVzLmxhdGVzdCAlPD4lIG11dGF0ZShyYW5raW5nID0gZGVuc2VfcmFuayhkZXNjKGNvbmZpcm1lZCkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlybWVkLnJhdGUgPSAoMTAwICogY29uZmlybWVkIC8gUG9wdWxhdGlvbikgJT4lIHJvdW5kKDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVhdGgucmF0ZSA9ICgxMDAgKiBkZWF0aHMgLyBjb25maXJtZWQpICU+JSByb3VuZCgyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIE1hbGUuY29uZmlybWVkID0gKE1hbGUgKiBjb25maXJtZWQpICU+JSByb3VuZCgwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIEZlbWFsZS5jb25maXJtZWQgPSBGZW1hbGUgKiBjb25maXJtZWQgJT4lIHJvdW5kKDApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgTWFsZS5kZWF0aHMgPSBNYWxlICogZGVhdGhzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgRmVtYWxlLmRlYXRocyA9IEZlbWFsZSAqIGRlYXRocykgJT4lDQogIGFycmFuZ2UocmFua2luZykgDQoNCnRvcC51cyA8LSBkYXRhLnVzLmxhdGVzdFssMV0NCnRvcC51cw0KDQojVmlldyh0b3AudXMpDQoNCmRhdGEudXMubGF0ZXN0LnNob3cgPC0gZGF0YS51cy5sYXRlc3QgJT4lIHNlbGVjdChzdGF0ZSxkYXRlLGNvbmZpcm1lZCxkZWF0aHMsIGNvbmZpcm1lZC5yYXRlLCBkZWF0aC5yYXRlKQ0KI1ZpZXcoZGF0YS51cy5sYXRlc3Quc2hvdykNCmBgYA0KDQpgYGB7cn0NCiMgTGlzdCBvZiB0b3AgMjAgc3RhdGUNCmsgPC0gMjANCmRhdGEudXMudG9wIDwtIGRhdGEudXMubGF0ZXN0ICU+JQ0KICBmaWx0ZXIocmFua2luZyA8PSBrKzEpICU+JSANCiAgYXJyYW5nZShyYW5raW5nKSANCiNWaWV3KGRhdGEudXMudG9wKQ0KDQp1cy5zdGF0ZS50b3AgPC0gZGF0YS51cy50b3AgJT4lIHB1bGwoc3RhdGUpICU+JSBhcy5jaGFyYWN0ZXIoKQ0KdXMuc3RhdGUudG9wICAlPiUgc2V0ZGlmZignVVMnKSAlPiUgcHJpbnQoKQ0KDQojIGNvbmZpcm1lZCByYXRlICYgZGVhdGggcmF0ZSBvZiB0b3AgMjAgc3RhdGUNCmcucmF0ZSA8LSBkYXRhLnVzLmxhdGVzdCAlPiUgZmlsdGVyKHN0YXRlICVpbiUgdXMuc3RhdGUudG9wICYgc3RhdGUgIT0gIlVTIikgJT4lDQogIHNlbGVjdChzdGF0ZSwgY29uZmlybWVkLnJhdGUsIGRlYXRoLnJhdGUsIHJhbmtpbmcpICU+JQ0KICBnYXRoZXIoa2V5ID0gVHlwZSwgdmFsdWUgPSBQZXJjZW50LCAtYyhzdGF0ZSwgcmFua2luZykpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihzdGF0ZSwgLWRlc2MocmFua2luZykpLCB5PVBlcmNlbnQsIGZpbGwgPSBQZXJjZW50KSkgKw0KICBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAiI2ViYmM2MiIsIGhpZ2ggPSAiI2I0MjAwNiIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1QZXJjZW50LCB5PVBlcmNlbnQpLCBzaXplPTMsIHZqdXN0PTApICsNCiAgeGxhYignJykgKyB5bGFiKCcnKSArDQogIGxhYnModGl0bGU9cGFzdGUwKCdDb25maXJtZWQgUmF0ZSAmIERlYXRoIFJhdGUgb2YgVG9wIDIwIFN0YXRlIGluIFVTJykpICsNCiAgI3NjYWxlX2ZpbGxfY29udGludW91cyhuYW1lPSdTdGF0ZScsIGxhYmVscz1hZXMoUGVyY2VudCkpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSdub25lJywNCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMyksDQogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkgKw0KICBmYWNldF93cmFwKH5UeXBlLCBuY29sPTEsIHNjYWxlcz0nZnJlZV95JykgDQoNCmcucmF0ZQ0KYGBgDQoNCmBgYHtyfQ0KdXMuY29uZmlybWVkLm51bSA8LSBkYXRhLnVzLnRvcCRjb25maXJtZWRbZGF0YS51cy50b3Akc3RhdGUgPT0gIlVTIl0gJT4lIGFzLm51bWVyaWMoKQ0KdXMuY29uZmlybWVkLm51bQ0KDQpkYXRhLnVzLnRvcCAlPD4lIG11dGF0ZShjb25maXJtZWQucGVyLnVzID0gKGNvbmZpcm1lZCAqIDEwMCAvIHVzLmNvbmZpcm1lZC5udW0pICU+JSByb3VuZCgxKSkNCmRhdGEudXMudG9wDQoNCmcudXMudG9wMSA8LSBkYXRhLnVzLnRvcCAlPiUNCiAgZmlsdGVyKHN0YXRlICE9ICJVUyIpICU+JQ0KICBzZWxlY3Qoc3RhdGUsIGNvbmZpcm1lZCwgY29uZmlybWVkLnBlci51cywgcmFua2luZykgJT4lDQogIGdhdGhlcihrZXkgPSBUeXBlLCB2YWx1ZSA9IGNvdW50LCAtYyhzdGF0ZSwgcmFua2luZywgY29uZmlybWVkLnBlci51cykpICU+JQ0KICBhcnJhbmdlKHJhbmtpbmcpICU+JQ0KICANCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihzdGF0ZSwgcmFua2luZyksIHkgPSBjb3VudCwgZmlsbCA9IGNvdW50KSkgKyANCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgI2xhYnModGl0bGUgPSAiMjAgc3RhdGUgaW4gVVMgd2l0aCBtb3N0IGNvbmZpcm1lZCBjYXNlcyIpICsNCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gIiM5M0RCRkYiLCBoaWdoID0gIiNGRjc3NzEiKSArDQogIHhsYWIoIiIpICsgDQogIHlsYWIoIkNvbmZpcm1lZCBDYXNlcyIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wYXN0ZTAoY29uZmlybWVkLnBlci51cywgIiUiKSksIHNpemU9Mywgdmp1c3Q9LTAuNSkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLHZqdXN0ID0gMC41KSkrDQogIHRoZW1lKA0KICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAjbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkNCg0KZy51cy50b3AxDQoNCmdseS51cy50b3AxIDwtIGdncGxvdGx5KGcudXMudG9wMSkNCmdseS51cy50b3AxDQpgYGANCg0KYGBge3J9DQpkYXRhLnVzLmxhdGVzdC5jb3JyIDwtIGRmX3VzICU+JWZpbHRlcihkYXRlPT1tYXguZGF0ZS51cykNCiNWaWV3KGRhdGEudXMubGF0ZXN0LmNvcnIpDQoNCmRhdGEudXMubGF0ZXN0LmNvcnIgJTw+JSBtdXRhdGUocmFua2luZyA9IGRlbnNlX3JhbmsoZGVzYyhjb25maXJtZWQpKSkgJT4lIGFycmFuZ2UocmFua2luZykNCnRvcC51cyA8LSBkYXRhLnVzLmxhdGVzdC5jb3JyWywyXQ0KI3RvcC51cw0KDQojIExpc3Qgb2YgdG9wIDIwIHN0YXRlDQprIDwtIDE5DQpkYXRhLnVzLmxhdGVzdC50b3AgPC0gZGF0YS51cy5sYXRlc3QuY29yciAlPiUNCiAgICBmaWx0ZXIocmFua2luZyA8PSBrKzEpICU+JSANCiAgICBhcnJhbmdlKHJhbmtpbmcpIA0KI1ZpZXcoZGF0YS51cy5sYXRlc3QudG9wKQ0KdXMuc3RhdGUudG9wIDwtIGRhdGEudXMubGF0ZXN0LnRvcCAlPiUgcHVsbChzdGF0ZSkgJT4lIGFzLmNoYXJhY3RlcigpDQp1cy5zdGF0ZS50b3AgICU+JSBzZXRkaWZmKCdVUycpICU+JSBwcmludCgpDQojVmlldyh1cy5zdGF0ZS50b3ApDQpgYGANCg0KDQoNCmBgYHtyfQ0KI2dlbmRlciBpbiB1cw0KZGZfdXNfZ2VuZGVyIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGRhdGFfZ2VuZGVyIikpDQpkZl91c19nZW5kZXIgPC0gYXMuZGF0YS5mcmFtZShkZl91c19nZW5kZXIpDQpkZl91c19nZW5kZXIgPC0gc2VsZWN0KGRmX3VzX2dlbmRlcixjKCJTdGF0ZSIsIk1hbGUiLCJGZW1hbGUiKSkNCmRmX3VzX2dlbmRlciA8LSByZW5hbWUoZGZfdXNfZ2VuZGVyLCJzdGF0ZSI9IlN0YXRlIikNCmRmX3VzX2dlbmRlcg0KDQojcG9wdWxhdGlvbiBpbiB1cw0KZGZfdXNfcG9wIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGRhdGFfcG9wdWxhdGlvbiIpKQ0KZGZfdXNfcG9wIDwtIGFzLmRhdGEuZnJhbWUoZGZfdXNfcG9wKQ0KZGZfdXNfcG9wIDwtIHNlbGVjdChkZl91c19wb3AsYygiU3RhdGUiLCJQb3B1bGF0aW9uIikpDQpkZl91c19wb3AgPC0gcmVuYW1lKGRmX3VzX3BvcCwic3RhdGUiPSJTdGF0ZSIpDQpkZl91c19wb3ANCg0KI2xvY2tkb3duIGluIHVzDQpkZl91c19sb2NrZG93biA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBkYXRhX2xvY2tkb3duIikpDQpkZl91c19sb2NrZG93biA8LSBhcy5kYXRhLmZyYW1lKGRmX3VzX2xvY2tkb3duKQ0KZGZfdXNfbG9ja2Rvd24gPC0gc2VsZWN0KGRmX3VzX2xvY2tkb3duLGMoIlN0YXRlIiwiRGF5IGxvY2tkb3duIikpDQpkZl91c19sb2NrZG93biA8LSByZW5hbWUoZGZfdXNfbG9ja2Rvd24sInN0YXRlIj0iU3RhdGUiKQ0KZGZfdXNfbG9ja2Rvd24NCg0KI0dEUCBpbiB1cw0KZGZfdXNfZ2RwIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIHVzX2dkcCIpKQ0KZGZfdXNfZ2RwICA8LSBhcy5kYXRhLmZyYW1lKGRmX3VzX2dkcCApDQpkZl91c19nZHAgIDwtIHNlbGVjdChkZl91c19nZHAgLGMoIlN0YXRlIiwiR0RQcyIpKQ0KZGZfdXNfZ2RwICA8LSByZW5hbWUoZGZfdXNfZ2RwICwic3RhdGUiPSJTdGF0ZSIpDQpkZl91c19nZHAgDQoNCiNob21lbGVzcyBpbiB1cw0KZGZfdXNfaG9tZWxlc3MgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gdXNfaG9tZWxlc3MiKSkNCmRmX3VzX2hvbWVsZXNzIDwtIGFzLmRhdGEuZnJhbWUoZGZfdXNfaG9tZWxlc3MpDQpkZl91c19ob21lbGVzcyA8LSBzZWxlY3QoZGZfdXNfaG9tZWxlc3MsYygiU3RhdGUiLCJIb21lbGVzcyIpKQ0KZGZfdXNfaG9tZWxlc3MgPC0gcmVuYW1lKGRmX3VzX2hvbWVsZXNzLCJzdGF0ZSI9IlN0YXRlIikNCmRmX3VzX2hvbWVsZXNzDQoNCiNWaWV3KGRmX3VzKQ0KDQoNCmBgYA0KYGBge3J9DQojbWVyZ2UNCm1lcmdjb3VudHJ5ID0gZnVuY3Rpb24oZGF0YTEsZGF0YTIpew0KICBkYXRhIDwtIG1lcmdlKHggPSBkYXRhMSwgeSA9IGRhdGEyLCBieSA9ICJzdGF0ZSIsIGFsbC54ID0gVFJVRSkgDQogIHJldHVybihkYXRhKQ0KfQ0KDQpkYXRhLnRvcC5zdGF0ZSA8LSBkYXRhLnVzLmxhdGVzdC50b3AgJT4lIGZpbHRlcihzdGF0ZSAhPSAiVVMiKSAlPiUNCiAgc2VsZWN0KHN0YXRlLCBjb25maXJtZWQsIGRlYXRocykNCiNWaWV3KGRhdGEudG9wLnN0YXRlKQ0KDQpkZl9BbGx1cyA8LSBtZXJnY291bnRyeShkYXRhLnRvcC5zdGF0ZSwgZGZfdXNfZ2VuZGVyKQ0KDQpkZl9BbGx1cyA8LSBtZXJnY291bnRyeShkZl9BbGx1cywgZGZfdXNfcG9wKSANCg0KZGZfQWxsdXMgPC0gbWVyZ2NvdW50cnkoZGZfQWxsdXMsIGRmX3VzX2xvY2tkb3duKSANCg0KZGZfQWxsdXMgPC0gbWVyZ2NvdW50cnkoZGZfQWxsdXMsIGRmX3VzX2dkcCkNCg0KZGZfQWxsdXMgPC0gbWVyZ2NvdW50cnkoZGZfQWxsdXMsIGRmX3VzX2hvbWVsZXNzKQ0KDQojVmlldyhkZl9BbGx1cykNCmBgYA0KDQpgYGB7cn0NCmluZGV4IDwtIGlzLm5hKGRmX0FsbHVzKQ0KZGZfQWxsdXNbaW5kZXhdIDwtIDANCiNWaWV3KGRmX0FsbHVzKQ0KDQpub3JtYWxpemUgPSBmdW5jdGlvbihkYXRhKXsNCiAgI3JldHVybiAoKGRhdGEgLSBtaW4oZGF0YSxuYS5ybSA9IFRSVUUpKS8obWF4KGRhdGEsbmEucm0gPSBUUlVFKSAtIG1pbihkYXRhLG5hLnJtID0gVFJVRSkpKQ0KICB6IDwtIHNjYWxlKGRhdGEpOw0KICB0YW5oKHovMikNCn0NCkFsbHVzID0gYXMuZGF0YS5mcmFtZShhcHBseShkZl9BbGx1c1ssMjo5XSwyLG5vcm1hbGl6ZSkpDQpjb3JyX2RhdGFVUyA8LSBBbGx1cyANCg0KI1ZpZXcoY29ycl9kYXRhVVMpDQpgYGANCg0KYGBge3J9DQpBbGx1cyRzdGF0ZSA8LSBjKGRmX0FsbHVzJHN0YXRlKQ0KI1ZpZXcoQWxsdXMpDQoNCmNvcnJfZGF0YVVTIDwtIHJlbmFtZShjb3JyX2RhdGFVUyAsIkRheWxvY2tkb3duIiA9ICJEYXkgbG9ja2Rvd24iKQ0KYGBgDQoNCmBgYHtyfQ0KQWxsdXNfcGxvdCA8LSBzZWxlY3QoQWxsdXMsInN0YXRlIiwiY29uZmlybWVkIiwiZGVhdGhzIiwiTWFsZSIsIkZlbWFsZSIsIlBvcHVsYXRpb24iLCJEYXkgbG9ja2Rvd24iLCJHRFBzIiwiSG9tZWxlc3MiKQ0KQWxsdXNfcGxvdCAlPD4lIGdhdGhlcihrZXk9dHlwZSwgdmFsdWU9Y291bnQsIC1jKHN0YXRlKSkNCmxldmVsX29yZGVyIDwtIGZhY3RvcihBbGx1c19wbG90JHR5cGUsIA0KICAgICAgICAgICAgICAgICAgICAgIGxldmVsID0gYygiY29uZmlybWVkIiwiZGVhdGhzIiwiTWFsZSIsIkZlbWFsZSIsIlBvcHVsYXRpb24iLCJEYXkgbG9ja2Rvd24iLCJHRFBzIiwiSG9tZWxlc3MiKSkNCg0KQWxsdXNfSGVhdCA8LSBBbGx1c1ssYyhuY29sKEFsbHVzKSwxOihuY29sKEFsbHVzKS0xKSldDQpyb3duYW1lcyhBbGx1c19IZWF0KSA8LSBBbGx1c19IZWF0WywxXQ0KQWxsdXNfSGVhdFssMV0gPC0gTlVMTA0KaGVhdG1hcC4yKGFzLm1hdHJpeChBbGx1c19IZWF0KSwNCiAgICAgICAgICAgICAgICAgICAgc2NhbGU9Im5vbmUiLCANCiAgICAgICAgICAgICAgICAgICAgY29sID0gY29sb3JSYW1wUGFsZXR0ZShjKCIjNkQ5RUMxIiwid2hpdGUiLCIjRTQ2NzI2IikpKG4gPSAyMDApLA0KICAgICAgICAgICAgICAgICAgICBtYXJnaW5zPWMoMTAsNiksdHJhY2U9ImNvbHVtbiIpDQoNCmhlYXRtYXB1cyA8LSBnZ3Bsb3QoZGF0YSA9IEFsbHVzX3Bsb3QsIGFlcyh4PXN0YXRlLCB5PWxldmVsX29yZGVyLCBmaWxsPWNvdW50KSkgKyANCiAgZ2VvbV90aWxlKCkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJwaW5rIiwgaGlnaCA9ICJibHVlIikgKw0KICB4bGFiKCIiKSArDQogIHlsYWIoIiIpICsNCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsdmp1c3QgPSAxKSkrDQogIHRoZW1lKA0KICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAjbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkgK2xhYnModGl0bGU9J1RoZSBoZWF0bWFwIG9mIENPVklELTE5IGluZmVjdGlvbnMgaW4gVVMnKQ0KDQpoZWF0bWFwdXMNCmBgYA0KDQoNCmBgYHtyfQ0KI2NvcnJlbGF0aW9uDQpjb3JyX2RhdGFVUyAlPD4lIHNlbGVjdChjKGNvbmZpcm1lZCxkZWF0aHMsTWFsZSxGZW1hbGUsUG9wdWxhdGlvbixEYXlsb2NrZG93bixHRFBzLEhvbWVsZXNzKSkNCmhlYWQoY29ycl9kYXRhVVMpDQpjb3IoY29ycl9kYXRhVVMpDQpnZ2NvcnJwbG90KGNvcihjb3JyX2RhdGFVUyksaGMub3JkZXIgPSBUUlVFLA0KICAgICAgICAgICBvdXRsaW5lLmNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgICAgY29sb3JzID0gYygiIzZEOUVDMSIsIndoaXRlIiwiI0U0NjcyNiIpLA0KICAgICAgICAgICBsYWIgPSBUUlVFKQ0KDQoNCg0KYGBgDQoNCmBgYHtyfQ0KI0NvdmlkX1RoYWlsYW5kDQpkZl90aGFpIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGNvdmlkMTlfdGhhaWxhbmQiKSkNCmRmX3RoYWkgPC0gYXMuZGF0YS5mcmFtZShkZl90aGFpKQ0KI1ZpZXcoZGZfdGhhaSkNCmBgYA0KDQpgYGB7cn0NCiNjbGVhbiBDb3ZpZF9UaGFpbGFuZA0KZGF0ZXMudGggPC0gZGZfdGhhaVssMl0lPiUgbWR5KCkNCnJhbmdlKGRhdGVzLnRoKQ0KbWluLmRhdGUudGggPC0gbWluKGRhdGVzLnRoKQ0KbWF4LmRhdGUudGggPC0gbWF4KGRhdGVzLnRoKQ0KbWluLmRhdGUudHh0LnRoIDwtIG1pbi5kYXRlLnRoICU+JSBmb3JtYXQoJyVkICViICVZJykNCm1heC5kYXRlLnR4dC50aCA8LSBtYXguZGF0ZS50aCAlPiUgZm9ybWF0KCclZCAlYiAlWScpDQpgYGANCg0KYGBge3J9DQpkZl90aGFpJGFubm91bmNlX2RhdGUgPC0gbWR5KGRmX3RoYWkkYW5ub3VuY2VfZGF0ZSkNCmRmX3RoYWkkbm90aWZpY2F0aW9uX2RhdGUgPC0gbWR5KGRmX3RoYWkkbm90aWZpY2F0aW9uX2RhdGUpDQpkZl90aGFpDQpgYGANCg0KYGBge3J9DQpkZl90aGFpIDwtIGRmX3RoYWkgJT4lIHNlbGVjdCghTm8uKSAlPiUgc2VsZWN0KCFub3RpZmljYXRpb25fZGF0ZSkgJT4lIA0KICBncm91cF9ieShhbm5vdW5jZV9kYXRlKQ0KZGZfdGhhaQ0KVmlldyhkZl90aGFpKQ0KYGBgDQoNCmBgYHtyfQ0KIyBUb3RhbCBjb25maXJtZWQgY2FzZXMgaW4gVGhhaWxhbmQNCmRhdGEudGhhaS5jb3VudCA8LSBkZl90aGFpICU+JQ0KICBzZWxlY3QoYW5ub3VuY2VfZGF0ZSkgJT4lDQogIHN1bW1hcmlzZShjb25maXJtZWQgPSBuKCkpICU+JSBhcy5kYXRhLmZyYW1lKCkNClZpZXcoZGF0YS50aGFpLmNvdW50KQ0KZGF0YS50aGFpLmNvdW50JGN1bXVsYXRpdmVfY29uZmlybWVkIDwtIGN1bXN1bShkYXRhLnRoYWkuY291bnRbLCAyXSkNCmBgYA0KYGBge3J9DQpkYXRhLnRoYWkuY291bnQgPC0gZGF0YS50aGFpLmNvdW50ICU+JSByZW5hbWUobmV3LmNvbmZpcm1lZD1jb25maXJtZWQpICU+JSByZW5hbWUoY29uZmlybWVkPWN1bXVsYXRpdmVfY29uZmlybWVkKQ0KdGhhaS50b3RhbC5sb25nIDwtIGRhdGEudGhhaS5jb3VudCAlPiUgDQogIGdhdGhlcihrZXkgPSB0eXBlLCB2YWx1ZSA9IGNvdW50LCAtYyhhbm5vdW5jZV9kYXRlKSkNCnRoYWkudG90YWwubG9uZw0KYGBgDQoNCmBgYHtyfQ0KDQpwbG90X3RoYWlsYW5kLmNvbmYgPC0gdGhhaS50b3RhbC5sb25nICU+JQ0KICBmaWx0ZXIodHlwZSAlaW4lIGMoIm5ldy5jb25maXJtZWQiKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGFubm91bmNlX2RhdGUsIHkgPSBjb3VudCwgY29sb3IgPSB0eXBlKSkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgeGxhYigiRGF0ZSIpICsNCiAgeWxhYigiY2FzZXMiKQ0KDQpnbHkucGxvdF90aGFpLmNhc2VzIDwtIGdncGxvdGx5KHBsb3RfdGhhaWxhbmQuY29uZikNCmdseS5wbG90X3RoYWkuY2FzZXMgPC0gZ2x5LnBsb3RfdGhhaS5jYXNlcyAlPiUgDQogIGxheW91dCh0aXRsZSA9IHBhc3RlMCgiPGI+RGFpbHkgVGhhaSBDb25maXJtZWQgQ2FzZXMgaW4gVGhhaWxhbmQgOiBKYW4gMjAyMCAtIEphbiAyMDIxIiksIA0KICAgICAgICAgZm9udD1saXN0KHNpemUgPSAxMCkpDQoNCmdseS5wbG90X3RoYWkuY2FzZXMNCmBgYA0KYGBge3J9DQpwbG90X3RoYWlsYW5kLmN1bXVsYXRpdmUgPC0gdGhhaS50b3RhbC5sb25nICU+JSANCiAgZmlsdGVyKHR5cGUgJWluJSBjKCJjb25maXJtZWQiKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGFubm91bmNlX2RhdGUsIHkgPSBjb3VudCkpICsNCiAgZ2VvbV9hcmVhKGFlcyhmaWxsPXR5cGUpLCBhbHBoYT0wLjUpICsNCg0KICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9J2xvZzEwJykgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygncmVkJykpKw0KICB5bGFiKCIiKSArDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04KSkNCg0KZ2x5LnBsb3RfdGhhaS5jdW11bGF0aXZlIDwtIGdncGxvdGx5KHBsb3RfdGhhaWxhbmQuY3VtdWxhdGl2ZSkNCmdseS5wbG90X3RoYWkuY3VtdWxhdGl2ZSA8LSBnbHkucGxvdF90aGFpLmN1bXVsYXRpdmUgJT4lIA0KICBsYXlvdXQodGl0bGUgPSBwYXN0ZTAoIjxiPkN1bXVsYXRpdmUgQ2FzZXMgaW4gVGhhaWxhbmQgOiBKYW4gMjAyMCAtIEphbiAyMDIxIChTdGFjayxMb2cgc2NhbGUpIiksIA0KICAgICAgICAgZm9udD1saXN0KHNpemUgPSAxMCkpDQoNCmdseS5wbG90X3RoYWkuY3VtdWxhdGl2ZQ0KYGBgDQoNCg0KDQpgYGB7cn0NCiMjIFRoYWkgQ29uZmlybWVkIENhc2VzIChKYW4gMjAyMCAtIEphbiAyMDIxDQpwbG90MSA8LSBnZ3Bsb3QoZGF0YS50aGFpLmNvdW50LCBhZXMoeD1hbm5vdW5jZV9kYXRlLCB5PWNvbmZpcm1lZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoIiAiKSArIHlsYWIoIkNvdW50IikgKyBsYWJzKHRpdGxlPSdUaGFpIEN1bXVsYXRpdmUgQ29uZmlybWVkIENhc2VzIChKYW4gMjAyMCAtIEphbiAyMDIxKScpICsNCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkNCnBsb3QyIDwtIGdncGxvdChkYXRhLnRoYWkuY291bnQsIGFlcyh4PWFubm91bmNlX2RhdGUsIHk9bmV3LmNvbmZpcm1lZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogICAgeGxhYigiICIpICsgeWxhYigiQ291bnQiKSsgbGFicyh0aXRsZT0nVGhhaSBDb25maXJtZWQgQ2FzZXMgKEphbiAyMDIwIC0gSmFuIDIwMjEgbG9nIHNjYWxlKScpICsNCiAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpK3NjYWxlX3lfY29udGludW91cyh0cmFucz0nbG9nMTAnKQ0KIyMgc2hvdyB0d28gcGxvdHMgc2lkZSBieSBzaWRlDQpncmlkLmFycmFuZ2UocGxvdDEsIHBsb3QyLCBuY29sPTEpDQpgYGANCg0KDQoNCmBgYHtyfQ0KIyBDb25maXJtZWQgY2FzZXMgZGl2aWRlZCBieSBzZXggKGdlbmRlcikNCmRmX3RoYWkkc2V4W2RmX3RoYWkkc2V4ID09ICIiXSA8LSAiVW5rbm93biINCmRhdGEudGhhaS5nZW5kZXIgPC0gZGZfdGhhaSAlPiUNCiAgZ3JvdXBfYnkoc2V4KSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiAgbXV0YXRlKHBlcmNlbnQgPSAoY291bnQgLyBzdW0oY291bnQpICogMTAwKSAlPiUgcm91bmQoMikpICU+JQ0KICBmaWx0ZXIocGVyY2VudD4xKSU+JQ0KICAjbXV0YXRlKHBvcyA9IGN1bXN1bShwZXJjZW50KSAtIDAuNSpwZXJjZW50KSAlPiUNCiAgYXJyYW5nZShkZXNjKHBlcmNlbnQpKQ0KDQpkYXRhLnRoYWkuZ2VuZGVyDQpgYGANCg0KYGBge3J9DQpkYXRhLnRoYWkuZ2VuZGVyJHNleCA8LSBmYWN0b3IoZGF0YS50aGFpLmdlbmRlciRzZXgsIGxldmVscyA9IGFzLmNoYXJhY3RlcihkYXRhLnRoYWkuZ2VuZGVyJHNleCkpDQpkYXRhLnRoYWkuZ2VuZGVyJHNleA0KZy50aC5nZW5kZXIgPC0gZGF0YS50aGFpLmdlbmRlciAlPiUgDQogIGdncGxvdChhZXMoeCA9ICIiLCB5ID0gcGVyY2VudCwgZmlsbCA9IHNleCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcigieSIpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgbGFicyh0aXRsZT0nR2VuZGVyIG9mIFRoYWkgQ29uZmlybWVkIENhc2VzIChKYW4gMjAyMCAtIEphbiAyMDIxKScpKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHBlcmNlbnQsICIlIikpLCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSA1LCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKw0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVFJVRSkpIA0KZy50aC5nZW5kZXINCmBgYA0KDQpgYGB7cn0NCiMgQ29uZmlybWVkIGNhc2VzIGRpdmlkZWQgYnkgcHJvdmluY2Vfb2Zfb25zZXQNCmRhdGEudGhhaS5vbnNldCA8LSBkZl90aGFpICU+JQ0KICAgIGdyb3VwX2J5KHByb3ZpbmNlX29mX29uc2V0KSAlPiUNCiAgICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICAgIGFycmFuZ2UoZGVzYyhjb3VudCkpJT4lDQogICAgcmVuYW1lKG9uc2V0PSJjb3VudCIpJT4lDQogICAgcmVuYW1lKHByb3ZpbmNlPSJwcm92aW5jZV9vZl9vbnNldCIpDQpkYXRhLnRoYWkub25zZXQkcHJvdmluY2VbZGF0YS50aGFpLm9uc2V0JHByb3ZpbmNlID09ICIiXSA8LSAiVW5rbm93biINCmRhdGEudGhhaS5vbnNldA0KYGBgDQoNCmBgYHtyfQ0KIyBDb25maXJtZWQgY2FzZXMgZGl2aWRlZCBieSBwcm92aW5jZV9vZl9pc29sYXRpb24gDQpkYXRhLnRoYWkuaXNvbGF0aW9uIDwtIGRmX3RoYWkgJT4lDQogICAgZ3JvdXBfYnkocHJvdmluY2Vfb2ZfaXNvbGF0aW9uKSAlPiUNCiAgICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICAgIGFycmFuZ2UoZGVzYyhjb3VudCkpJT4lDQogICAgcmVuYW1lKGlzb2xhdGlvbiA9ImNvdW50IiklPiUNCiAgICByZW5hbWUocHJvdmluY2U9InByb3ZpbmNlX29mX2lzb2xhdGlvbiIpDQoNCmRhdGEudGhhaS5pc29sYXRpb24kcHJvdmluY2VbZGF0YS50aGFpLmlzb2xhdGlvbiRwcm92aW5jZSA9PSAiIl0gPC0gIlVua25vd24iDQpkYXRhLnRoYWkuaXNvbGF0aW9uDQpgYGANCg0KYGBge3J9DQpkYXRhLnByb3ZpbmNlIDwtIG1lcmdlKHggPSBkYXRhLnRoYWkub25zZXQsIHkgPSBkYXRhLnRoYWkuaXNvbGF0aW9uLCBieSA9ICJwcm92aW5jZSIsIGFsbC54ID0gVFJVRSkgDQpkYXRhLnByb3ZpbmNlIDwtIGRhdGEucHJvdmluY2UlPiVmaWx0ZXIob25zZXQ+MTI1KQ0KZGF0YS5wcm92aW5jZQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YS5wcm92aW5jZS5sb25nIDwtIGRhdGEucHJvdmluY2UgJT4lDQogICAgZ2F0aGVyKGtleT10eXBlLCB2YWx1ZT1jb3VudCwgLWMocHJvdmluY2UpKQ0KZGF0YS5wcm92aW5jZS5sb25nDQpgYGANCg0KYGBge3J9DQpwcm92aW5jZS50aGFpIDwtIGdncGxvdChkYXRhLnByb3ZpbmNlLmxvbmcsYWVzKHg9cHJvdmluY2UseT1jb3VudCkpKw0KICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLHBvc2l0aW9uID0gImRvZGdlIixhZXMoZmlsbD10eXBlKSkrDQogICAgbGFicyh0aXRsZSA9ICJQcm92aW5jZSBvZiBvbnNldCBhbmQgUHJvdmluY2Ugb2YgaXNvbGF0aW9uIGluIFRoYWlsYW5kIikrDQogICAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICAgICNsZWdlbmQucG9zaXRpb249J25vbmUnLA0KICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMiksDQogICAgICAgICAgICAgICAgICBheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTApLA0KICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkrIHhsYWIoJycpICsgeWxhYignQ291bnQnKQ0KZ2x5LnByb3ZpbmNlLnRoYWkgPC0gZ2dwbG90bHkocHJvdmluY2UudGhhaSkNCmdseS5wcm92aW5jZS50aGFpDQpgYGANCg0KYGBge3J9DQojIENvbmZpcm1lZCBjYXNlcyBkaXZpZGVkIGJ5IHJpc2sNCmRhdGEudGhhaS5yaXNrIDwtIGRmX3RoYWkgJT4lDQogIGdyb3VwX2J5KHJpc2spICU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICBhcnJhbmdlKGRlc2MoY291bnQpKQ0KZGF0YS50aGFpLnJpc2sNCmBgYA0KDQpgYGB7cn0NCiMgQ29uZmlybWVkIGNhc2VzIGRpdmlkZWQgYnkgcmlzaw0KZGF0YS50aGFpLnJpc2sgPC0gZGZfdGhhaSAlPiUNCiAgZ3JvdXBfYnkocmlzaykgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIG11dGF0ZShwZXJjZW50ID0gKGNvdW50IC8gc3VtKGNvdW50KSAqIDEwMCkgJT4lIHJvdW5kKDIpKSAlPiUNCiAgZmlsdGVyKHBlcmNlbnQ+NCkgJT4lDQogIGFycmFuZ2UoZGVzYyhwZXJjZW50KSkgDQpkYXRhLnRoYWkucmlzaw0KYGBgDQoNCmBgYHtyfQ0KZGF0YS50aGFpLnJpc2skcmlza1tkYXRhLnRoYWkucmlzayRyaXNrID09ICJDIl0gPC0gIkNsb3NlIGNvbnRhY3Qgd2l0aCB0aGUgcGF0aWVudCINCmRhdGEudGhhaS5yaXNrJHJpc2tbZGF0YS50aGFpLnJpc2skcmlzayA9PSAiQ0d1c3REciBTYW11dCBTYUdHQUYiXSA8LSAiQ2x1c3RlciBTYW11dCBTYWtob24iDQpkYXRhLnRoYWkucmlzayRyaXNrW2RhdGEudGhhaS5yaXNrJHJpc2sgPT0gIkYiXSA8LSAiU3RhdGUgUXVhcmFudGluZSINCmRhdGEudGhhaS5yaXNrJHJpc2tbZGF0YS50aGFpLnJpc2skcmlzayA9PSAiRyJdIDwtICJHbyB0byBhIGNyb3dkZWQgcGxhY2UiDQpkYXRhLnRoYWkucmlzayRyaXNrW2RhdGEudGhhaS5yaXNrJHJpc2sgPT0gIkEiXSA8LSAiUGVvcGxlIHRyYXZlbGxpbmcgZnJvbSBhYnJvYWQiDQpkYXRhLnRoYWkucmlzayRyaXNrW2RhdGEudGhhaS5yaXNrJHJpc2sgPT0gIlVGR0ZBd0YiXSA8LSAiVW5rbm93biINCmRhdGEudGhhaS5yaXNrJHJpc2tbZGF0YS50aGFpLnJpc2skcmlzayA9PSAiRCJdIDwtICJDYXJlZXIgYXQgcmlzayINCmRhdGEudGhhaS5yaXNrJHJpc2tbZGF0YS50aGFpLnJpc2skcmlzayA9PSAiQ0d1c3REciBSYXlBRmciXSA8LSAiQ2x1c3RlciBSYXlvbmciDQpkYXRhLnRoYWkucmlzayRyaXNrW2RhdGEudGhhaS5yaXNrJHJpc2sgPT0gIkNHdXN0RHIgUGF0dGF5YSBDYXNDRkEiXSA8LSAiQ2x1c3RlciBQYXR0YXlhIENhc2lubyINCmRhdGEudGhhaS5yaXNrJHJpc2tbZGF0YS50aGFpLnJpc2skcmlzayA9PSAiQ0d1c3REciBBRmcgVEdBRmciXSA8LSAiQ2x1c3RlciBBbmcgVGhvbmciDQpkYXRhLnRoYWkucmlzaw0KYGBgDQoNCmBgYHtyfQ0KZGF0YS50aGFpLnJpc2skcmlzayA8LSBmYWN0b3IoZGF0YS50aGFpLnJpc2skcmlzaywgbGV2ZWxzID0gYXMuY2hhcmFjdGVyKGRhdGEudGhhaS5yaXNrJHJpc2spKQ0KZGF0YS50aGFpLnJpc2skcmlzaw0KZy50aC5yaXNrIDwtIGRhdGEudGhhaS5yaXNrICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gIiIsIHkgPSBwZXJjZW50LCBmaWxsID0gcmlzaykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC41KSArDQogIGNvb3JkX3BvbGFyKCJ5IikgKw0KICB0aGVtZV92b2lkKCkgKw0KICBsYWJzKHRpdGxlPSdSaXNrIG9mIFRoYWkgQ29uZmlybWVkIENhc2VzKEphbiAyMDIwIC0gSmFuIDIwMjEpJykrDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocGVyY2VudCwgIiUiKSksIGNvbG9yID0gIkJsYWNrIiwgc2l6ZSA9IDMsIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSArDQogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFKSkgDQpnLnRoLnJpc2sNCmBgYA0KDQpgYGB7cn0NCiMgQ29uZmlybWVkIGNhc2VzIGRpdmlkZWQgYnkgYWdlDQpkYXRhLnRoYWkuYWdlIDwtIGRmX3RoYWkgJT4lDQogIGdyb3VwX2J5KGFnZSxzZXgpICU+JSANCiAgZmlsdGVyKGFnZSAhPSAwKSU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICBhcnJhbmdlKGRlc2MoY291bnQpKQ0KZGF0YS50aGFpLmFnZQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YS50aGFpLmFnZSA8LSBkYXRhLnRoYWkuYWdlIyAlPiUgZmlsdGVyKHNleCAhPSAiVW5rbm93biIpDQpnZ3Bsb3QoZGF0YS50aGFpLmFnZSxhZXMoeD1hZ2UseT1jb3VudCxmaWxsPXNleCkpK2dlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSsNCiAgICAgIGxhYnModGl0bGU9J0FnZSBvZiBUaGFpIENvbmZpcm1lZCBDYXNlcyAoU3RhY2spJykrZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUKSkNCmBgYA0KDQpgYGB7cn0NCiMgQ29uZmlybWVkIGNhc2VzIGRpdmlkZWQgYnkgbmF0aW9uYWxpdHkNCmRhdGEudGhhaS5uYXRpb25hbGl0eSA8LSBkZl90aGFpDQoNCmRhdGEudGhhaS5uYXRpb25hbGl0eSRuYXRpb25hbGl0eVtkYXRhLnRoYWkubmF0aW9uYWxpdHkkbmF0aW9uYWxpdHkgPT0gIj8/Pz8/Pz8/Il0gPC0gIlVua25vd24iDQpkYXRhLnRoYWkubmF0aW9uYWxpdHkkbmF0aW9uYWxpdHlbZGF0YS50aGFpLm5hdGlvbmFsaXR5JG5hdGlvbmFsaXR5ID09ICIiXSA8LSAiVW5rbm93biINCmRhdGEudGhhaS5uYXRpb25hbGl0eSRuYXRpb25hbGl0eVtkYXRhLnRoYWkubmF0aW9uYWxpdHkkbmF0aW9uYWxpdHkgPT0gIkJ1cm1hIl0gPC0gIk15YW5tYXIiDQoNCmRhdGEudGhhaS5uYXRpb25hbGl0eSA8LSBkYXRhLnRoYWkubmF0aW9uYWxpdHkgJT4lDQogIGdyb3VwX2J5KG5hdGlvbmFsaXR5KSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiAgZmlsdGVyKGNvdW50ID4gMTEpJT4lDQogIGFycmFuZ2UoZGVzYyhjb3VudCkpDQoNCmRhdGEudGhhaS5uYXRpb25hbGl0eQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YS50aGFpLm5hdGlvbmFsaXR5JGNvdW50W2RhdGEudGhhaS5uYXRpb25hbGl0eSRuYXRpb25hbGl0eSA9PSAiVW5rbm93biJdDQpnZ3Bsb3QoZGF0YS50aGFpLm5hdGlvbmFsaXR5LCBhZXMoeD1yZW9yZGVyKG5hdGlvbmFsaXR5LCBjb3VudCkseT1jb3VudCxmaWxsID0gY291bnQpKSsgDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLHNob3cubGVnZW5kID0gRikrDQogICAgZ2d0aXRsZSgnTmF0aW9uYWxpdHkgb2YgQ29uZmlybWVkIENhc2VzIGluIFRoYWlsYW5kIChsb2cgc2NhbGUpJykrDQogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpKw0KICAgIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLA0KICAgICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLA0KICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpKSsNCiAgICB4bGFiKCIiKSt5bGFiKCJOdW1iZXIgb2YgTmF0aW9uYWxpdHkiKSsNCiAgIHNjYWxlX3lfY29udGludW91cyh0cmFucz0nbG9nMTAnKStjb29yZF9mbGlwKCkrc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9ImJsdWUiLGhpZ2ggPSAicmVkIikNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0K
=======
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQojaW5zdGFsbC5wYWNrYWdlcygiZ3JpZCIpDQojaW5zdGFsbC5wYWNrYWdlcygiTUxSTVBBIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJkcHJlcCIpDQojaW5zdGFsbC5wYWNrYWdlcygibm9ybWFsciIpDQojaW5zdGFsbC5wYWNrYWdlcygiZ2djb3JycGxvdCIpDQojaW5zdGFsbC5wYWNrYWdlcygiUkNvbG9yQnJld2VyIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJyZ2RhbCIpDQojaW5zdGFsbC5wYWNrYWdlcygianNvbmxpdGUiKQ0KI2luc3RhbGwucGFja2FnZXMoIlJDb2xvckJyZXdlciIpDQojaW5zdGFsbC5wYWNrYWdlcygicmVhZHIiKQ0KU3lzLnNldGxvY2FsZSgiTENfQUxMIiwgIkVuZ2xpc2giKQ0KU3lzLnNldGVudigiTEFOR1VBR0UiPSJFbiIpDQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShtYWdyaXR0cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShub3JtYWxyKQ0KbGlicmFyeShnZ2NvcnJwbG90KQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCmxpYnJhcnkocmVhZHIpDQoNCiM/P3NyY19teXNxbA0KbXlfZGIgPC0gc3JjX215c3FsKA0KICBkYm5hbWUgPSAiY292aWQxOSIsDQogIGhvc3QgPSAiY3ZkLWRhdGFiYXNlLmNteHBueXlsaGtpdy51cy1lYXN0LTIucmRzLmFtYXpvbmF3cy5jb20iLA0KICB1c2VyID0gImFkbWluIiwNCiAgcGFzc3dvcmQgPSAiUnByb2plY3RDb3ZpZDE5Ig0KKQ0KbXlfZGINCg0KIyNpbXBvcnQgZGF0YQ0KZGZfY29uZiA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBjb3ZpZDE5X2NvbmZpcm1lZCIpKQ0KZGZfY29uZiA8LSBhcy5kYXRhLmZyYW1lKGRmX2NvbmYpDQpkZl9jb25mDQpkZl9kZWF0aHMgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gY292aWQxOV9kZWF0aHMiKSkNCmRmX2RlYXRocyA8LSBhcy5kYXRhLmZyYW1lKGRmX2RlYXRocykNCmRmX2RlYXRocw0KZGZfcmVjb3ZlciA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBjb3ZpZDE5X3JlY292ZXJlZCIpKQ0KZGZfcmVjb3ZlciA8LSBhcy5kYXRhLmZyYW1lKGRmX3JlY292ZXIpDQpkZl9yZWNvdmVyDQpgYGANCg0KYGBge3J9DQojI2NoZWNrIHRoZSB0aW1lIGZyYW1lIG9mIHRoZSBkYXRhDQpuLmNvbCA8LSBuY29sKGRmX2NvbmYpDQpkYXRlcyA8LSBuYW1lcyhkZl9jb25mKVs1Om4uY29sXSU+JSBtZHkoKQ0KcmFuZ2UoZGF0ZXMpDQptaW4uZGF0ZSA8LSBtaW4oZGF0ZXMpDQptYXguZGF0ZSA8LSBtYXgoZGF0ZXMpDQptaW4uZGF0ZS50eHQgPC0gbWluLmRhdGUgJT4lIGZvcm1hdCgnJWQgJWIgJVknKQ0KbWF4LmRhdGUudHh0IDwtIG1heC5kYXRlICU+JSBmb3JtYXQoJyVkICViICVZJykNCmBgYA0KYGBge3J9DQojY2xlYW4gZGF0YQ0KY2xlYW5EYXRhIDwtIGZ1bmN0aW9uKGRhdGEpIHsNCiAgIyMgcmVtb3ZlIHNvbWUgY29sdW1ucw0KICBkYXRhICU8PiUgc2VsZWN0KC1jKFByb3ZpbmNlLlN0YXRlLCBMYXQsIExvbmcpKSAlPiUgcmVuYW1lKGNvdW50cnk9Q291bnRyeS5SZWdpb24pDQogICMjIGNvbnZlcnQgZnJvbSB3aWRlIHRvIGxvbmcgZm9ybWF0DQogIGRhdGEgJTw+JSBnYXRoZXIoa2V5PWRhdGUsIHZhbHVlPWNvdW50LCAtY291bnRyeSkNCiAgIyMgY29udmVydCBmcm9tIGNoYXJhY3RlciB0byBkYXRlDQogIGRhdGEgJTw+JSBtdXRhdGUoZGF0ZSA9IGRhdGUgJT4lIG1keSgpKQ0KICAjIyBhZ2dyZWdhdGUgYnkgY291bnRyeQ0KICBkYXRhICU8PiUgZ3JvdXBfYnkoY291bnRyeSwgZGF0ZSkgJT4lIHN1bW1hcmlzZShjb3VudD1zdW0oY291bnQsIG5hLnJtPVQpKSAlPiUgYXMuZGF0YS5mcmFtZSgpDQogIHJldHVybihkYXRhKQ0KfQ0KIyMgY2xlYW4gdGhlIHRocmVlIGRhdGEgc2V0cw0KZGF0YS5jb25maXJtZWQgPC0gZGZfY29uZiAlPiUgY2xlYW5EYXRhKCkgJT4lIHJlbmFtZShjb25maXJtZWQ9Y291bnQpDQpkYXRhLmRlYXRocyA8LSBkZl9kZWF0aHMgJT4lIGNsZWFuRGF0YSgpICU+JSByZW5hbWUoZGVhdGhzPWNvdW50KQ0KZGF0YS5yZWNvdmVyZWQgPC0gZGZfcmVjb3ZlciAlPiUgY2xlYW5EYXRhKCkgJT4lIHJlbmFtZShyZWNvdmVyZWQ9Y291bnQpDQpkYXRhIDwtIGRhdGEuY29uZmlybWVkICU+JSBtZXJnZShkYXRhLmRlYXRocywgYWxsPVQpICU+JSBtZXJnZShkYXRhLnJlY292ZXJlZCwgYWxsPVQpDQpkYXRhDQojIyBjb3VudHJpZXMvcmVnaW9ucyB3aXRoIGNvbmZpcm1lZCBjYXNlcywgZXhjbC4gY3J1aXNlIHNoaXBzDQpjb3VudHJpZXMgPC0gZGF0YSAlPiUgcHVsbChjb3VudHJ5KSAlPiUgc2V0ZGlmZignQ3J1aXNlIFNoaXAnKQ0KZGF0YQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YS53b3JsZCA8LSBkYXRhICU+JSBncm91cF9ieShkYXRlKSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50cnk9J1dvcmxkJywNCiAgICAgICAgICAgIGNvbmZpcm1lZCA9IHN1bShjb25maXJtZWQsIG5hLnJtPVQpLA0KICAgICAgICAgICAgZGVhdGhzID0gc3VtKGRlYXRocywgbmEucm09VCksDQogICAgICAgICAgICByZWNvdmVyZWQgPSBzdW0ocmVjb3ZlcmVkLCBuYS5ybT1UKSkNCmRhdGEgJTw+JSByYmluZChkYXRhLndvcmxkKQ0KZGF0YQ0KZGF0YSAlPD4lIG11dGF0ZShjdXJyZW50LmNvbmZpcm1lZCA9IGNvbmZpcm1lZCAtIGRlYXRocyAtIHJlY292ZXJlZCkNCiNWaWV3KGRhdGEpDQpgYGANCg0KDQoNCmBgYHtyfQ0KIyBXb3JsZCBjb25maXJtZWQgY2FzZXMgbWFwDQp3b3JsZC5sb2NhdGlvbiA8LSBkZl9jb25mDQojVmlldyh3b3JsZC5sb2NhdGlvbiApDQp3b3JsZC5sb2NhdGlvbiRjb25maXJtZWQgPC0gd29ybGQubG9jYXRpb24gWywgbmNvbCh3b3JsZC5sb2NhdGlvbiApXQ0Kd29ybGQubG9jYXRpb24gICU8PiUgc2VsZWN0KGMoQ291bnRyeS5SZWdpb24sIFByb3ZpbmNlLlN0YXRlLCBMYXQsIExvbmcsIGNvbmZpcm1lZCkpICU+JQ0KICBtdXRhdGUodHh0PXBhc3RlMChDb3VudHJ5LlJlZ2lvbiwgJyAtICcsIFByb3ZpbmNlLlN0YXRlLCAnOiAnLCBjb25maXJtZWQpKQ0KbWFwLmNvbmZpcm1lZCA8LSBsZWFmbGV0KHdpZHRoPTEyMDAsIGhlaWdodD04MDApICU+JSBhZGRUaWxlcygpDQojIGNpcmNsZSBtYXJrZXIgKHVuaXRzIGluIHBpeGVscykNCm1hcC5jb25maXJtZWQgJTw+JSBhZGRDaXJjbGVNYXJrZXJzKHdvcmxkLmxvY2F0aW9uJExvbmcsIHdvcmxkLmxvY2F0aW9uJExhdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICMgcmFkaXVzPTIrbG9nMih4JGNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgICAgICAgICByYWRpdXM9MC4wMipzcXJ0KHdvcmxkLmxvY2F0aW9uJGNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgICAgICAgICBzdHJva2U9RiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPSdyZWQnLCBmaWxsT3BhY2l0eT0wLjMsDQogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD13b3JsZC5sb2NhdGlvbiR0eHQpDQojIHdvcmxkDQptYXAuY29uZmlybWVkDQpgYGANCg0KYGBge3J9DQojIyBDaGluYQ0KbWFwLmNvbmZpcm1lZCAlPiUgc2V0Vmlldyg5NSwgMzUsIHpvb209NCkNCiMjIEF1c3RyYWxpYSBhbmQgTmV3IFplYWxhbmQNCm1hcC5jb25maXJtZWQgJT4lIHNldFZpZXcoMTM1LCAtMjcsIHpvb209NCkNCiMjIFVTIGFuZCBDYW5hZGENCm1hcC5jb25maXJtZWQgJT4lIHNldFZpZXcoLTEwNSwgNDAsIHpvb209NCkNCiMjIEV1cm9wZQ0KbWFwLmNvbmZpcm1lZCAlPiUgc2V0VmlldygxMCwgNTAsIHpvb209NCkNCmBgYA0KDQpgYGB7cn0NCiMgbmV3LmNvbmZpcm1lZCBuZXcuZGVhdGhzIG5ldy5yZWNvdmVyZWQNCmRhdGEgJTw+JSBhcnJhbmdlKGNvdW50cnksIGRhdGUpDQpuIDwtIG5yb3coZGF0YSkNCmRheTEgPC0gbWluKGRhdGEkZGF0ZSkNCmRhdGEgJTw+JSBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCBjb25maXJtZWQgLSBsYWcoY29uZmlybWVkLCBuPTEpKSwNCiAgICAgICAgICAgICAgICAgbmV3LmRlYXRocyA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCBkZWF0aHMgLSBsYWcoZGVhdGhzLCBuPTEpKSwNCiAgICAgICAgICAgICAgICAgbmV3LnJlY292ZXJlZCA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCByZWNvdmVyZWQgLSBsYWcocmVjb3ZlcmVkLCBuPTEpKSkNCmRhdGEgJTw+JSBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShuZXcuY29uZmlybWVkIDwgMCwgMCwgbmV3LmNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgIG5ldy5kZWF0aHMgPSBpZmVsc2UobmV3LmRlYXRocyA8IDAsIDAsIG5ldy5kZWF0aHMpLA0KICAgICAgICAgICAgICAgICBuZXcucmVjb3ZlcmVkID0gaWZlbHNlKG5ldy5yZWNvdmVyZWQgPCAwLCAwLCBuZXcucmVjb3ZlcmVkKSkNCiMjIGRlYXRoIHJhdGUgYmFzZWQgb24gdG90YWwgZGVhdGhzIGFuZCByZWNvdmVyZWQgY2FzZXMNCmRhdGEgJTw+JSBtdXRhdGUocmF0ZS51cHBlciA9ICgxMDAgKiBkZWF0aHMgLyAoZGVhdGhzICsgcmVjb3ZlcmVkKSkgJT4lIHJvdW5kKDEpLA0KICAgICAgICAgICAgICAgICByYXRlLnVwcGVyID0gaWZlbHNlKGlzLm5hbihyYXRlLnVwcGVyKSwgMCwgcmF0ZS51cHBlcikpDQoNCiMjIGxvd2VyIGJvdW5kOiBkZWF0aCByYXRlIGJhc2VkIG9uIHRvdGFsIGNvbmZpcm1lZCBjYXNlcw0KZGF0YSAlPD4lIG11dGF0ZShyYXRlLmxvd2VyID0gKDEwMCAqIGRlYXRocyAvIGNvbmZpcm1lZCkgJT4lIHJvdW5kKDEpLA0KICAgICAgICAgICAgICAgICByYXRlLmxvd2VyID0gaWZlbHNlKGlzLm5hbihyYXRlLmxvd2VyKSwgMCwgcmF0ZS5sb3dlcikpDQoNCiMjIGRlYXRoIHJhdGUgYmFzZWQgb24gdGhlIG51bWJlciBvZiBkZWF0aC9yZWNvdmVyZWQgb24gZXZlcnkgc2luZ2xlIGRheQ0KZGF0YSAlPD4lIG11dGF0ZShyYXRlLmRhaWx5ID0gKDEwMCAqIG5ldy5kZWF0aHMgLyAobmV3LmRlYXRocyArIG5ldy5yZWNvdmVyZWQpKSAlPiUgcm91bmQoMSksDQogICAgICAgICAgICAgICAgIHJhdGUuZGFpbHkgPSBpZmVsc2UoaXMubmFuKHJhdGUuZGFpbHkpLCAwLCByYXRlLmRhaWx5KSkNCg0KI1ZpZXcoZGF0YSkNCmBgYA0KDQpgYGB7cn0NCiMjIGNvbnZlcnQgZnJvbSB3aWRlIHRvIGxvbmcgZm9ybWF0DQpkYXRhLmxvbmcgPC0gZGF0YSAlPiUNCiAgc2VsZWN0KGMoY291bnRyeSwgZGF0ZSwgY29uZmlybWVkLCBjdXJyZW50LmNvbmZpcm1lZCwgcmVjb3ZlcmVkLCBkZWF0aHMpKSAlPiUNCiAgZ2F0aGVyKGtleT10eXBlLCB2YWx1ZT1jb3VudCwgLWMoY291bnRyeSwgZGF0ZSkpDQojIyBzZXQgZmFjdG9yIGxldmVscyB0byBzaG93IHRoZW0gaW4gYSBkZXNpcmFibGUgb3JkZXINCmRhdGEubG9uZyAlPD4lIG11dGF0ZSh0eXBlPXJlY29kZV9mYWN0b3IodHlwZSwgY29uZmlybWVkPSdUb3RhbCBDb25maXJtZWQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50LmNvbmZpcm1lZD0nQ3VycmVudCBDb25maXJtZWQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNvdmVyZWQ9J1JlY292ZXJlZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlYXRocz0nRGVhdGhzJykpDQojVmlldyhkYXRhLmxvbmcpDQpgYGANCg0KYGBge3J9DQojI051bWJlciBvZiBjYXNlIFdvcmxkDQp3b3JsZCA8LSBmaWx0ZXIoZGF0YS5sb25nLGNvdW50cnkgPT0gJ1dvcmxkJykNCndvcmxkDQpwbG90X3dvcmxkLmFyZWEgPC0gd29ybGQgJT4lIGZpbHRlcih0eXBlICE9ICdUb3RhbCBDb25maXJtZWQnKSAlPiUNCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9Y291bnQpKSArDQogIGdlb21fYXJlYShhZXMoZmlsbD10eXBlKSwgYWxwaGE9MC41KSArDQogIGxhYnModGl0bGU9cGFzdGUwKCdOdW1iZXJzIG9mIENhc2VzIFdvcmxkd2lkZSAtICcsIG1heC5kYXRlLnR4dCkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoJ3JlZCcsICdncmVlbicsICdibGFjaycpKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj0nYm90dG9tJywNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTcpLA0KICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQua2V5LnNpemU9dW5pdCgwLjIsICdjbScpLA0KICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT02KSwNCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTcpLA0KICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdF93b3JsZC5saW5lIDwtIHdvcmxkICU+JQ0KICBnZ3Bsb3QoYWVzKHg9ZGF0ZSwgeT1jb3VudCxjb2xvciA9IHR5cGUpKSArDQogIGdlb21fbGluZShhZXMoY29sb3I9dHlwZSkpICsNCiAgbGFicyh0aXRsZT1wYXN0ZTAoJ051bWJlcnMgb2YgQ2FzZXMgV29ybGR3aWRlIChsb2cgc2NhbGUpIC0gJywgbWF4LmRhdGUudHh0KSkgKw0KICAjc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCdibHVlJywgJ3JlZCcsICdncmVlbicsICdibGFjaycpKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj0nYm90dG9tJywNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTcpLA0KICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQua2V5LnNpemU9dW5pdCgwLjIsICdjbScpLA0KICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT02KSwNCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTcpLA0KICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKSArDQogIHNjYWxlX3lfY29udGludW91cyh0cmFucz0nbG9nMTAnKQ0KIyMgc2hvdyB0d28gcGxvdHMgc2lkZSBieSBzaWRlDQpncmlkLmFycmFuZ2UocGxvdF93b3JsZC5hcmVhLCBwbG90X3dvcmxkLmxpbmUsIG5jb2w9MikNCg0KZ2x5LnBsb3Rfd29ybGQuYXJlYSA8LSBnZ3Bsb3RseShwbG90X3dvcmxkLmFyZWEpDQpnbHkucGxvdF93b3JsZC5hcmVhDQoNCmdseS5wbG90X3dvcmxkLmxpbmUgPC0gZ2dwbG90bHkocGxvdF93b3JsZC5saW5lKQ0KZ2x5LnBsb3Rfd29ybGQubGluZQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmRhdGEud29ybGQuYWxsIDwtIGRhdGEgJT4lIGZpbHRlcihjb3VudHJ5ID09ICJXb3JsZCIpDQojIyBhIHNjYXR0ZXIgcGxvdCB3aXRoIGEgc21vb3RoZWQgbGluZSBhbmQgdmVydGljYWwgeC1heGlzIGxhYmVscw0KcGxvdF9hY2MuZGVhdGhzIDwtIGdncGxvdChkYXRhLndvcmxkLmFsbCwgYWVzKHg9ZGF0ZSwgeT1kZWF0aHMpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdBY2N1bXVsYXRpdmUgRGVhdGhzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdF9yZWNvdmVyZWQgPC0gZ2dwbG90KGRhdGEud29ybGQuYWxsLCBhZXMoeD1kYXRlLCB5PXJlY292ZXJlZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J0FjY3VtdWxhdGl2ZSBSZWNvdmVyZWQgQ2FzZXMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQpwbG90X25ldy5kZWF0aHMgPC0gZ2dwbG90KGRhdGEud29ybGQuYWxsLCBhZXMoeD1kYXRlLCB5PW5ldy5kZWF0aHMpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdOZXcgRGVhdGhzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdF9uZXcucmVjb3ZlcmVkIDwtIGdncGxvdChkYXRhLndvcmxkLmFsbCwgYWVzKHg9ZGF0ZSwgeT1uZXcucmVjb3ZlcmVkKSkgKw0KICBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aCgpICsNCiAgeGxhYignJykgKyB5bGFiKCdDb3VudCcpICsgbGFicyh0aXRsZT0nTmV3IFJlY292ZXJlZCBDYXNlcycpICsNCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkNCiMjIHNob3cgZm91ciBwbG90cyB0b2dldGhlciwgd2l0aCAyIHBsb3RzIGluIGVhY2ggcm93DQpncmlkLmFycmFuZ2UocGxvdF9hY2MuZGVhdGhzLCBwbG90X3JlY292ZXJlZCwgcGxvdF9uZXcuZGVhdGhzLCBwbG90X25ldy5yZWNvdmVyZWQsIG5yb3c9MikNCg0KYGBgDQoNCmBgYHtyfQ0KIyMgY29udmVydCBmcm9tIHdpZGUgdG8gbG9uZyBmb3JtYXQsIGZvciBkcmF3aW5nIGFyZWEgcGxvdHMNCnJhdGVzLmxvbmcgPC0gZGF0YSAlPiUNCiAgc2VsZWN0KGMoY291bnRyeSwgZGF0ZSwgcmF0ZS51cHBlciwgcmF0ZS5sb3dlciwgcmF0ZS5kYWlseSkpICU+JQ0KICBnYXRoZXIoa2V5PXR5cGUsIHZhbHVlPWNvdW50LCAtYyhjb3VudHJ5LCBkYXRlKSkNCiMgc2V0IGZhY3RvciBsZXZlbHMgdG8gc2hvdyB0aGVtIGluIGEgZGVzaXJhYmxlIG9yZGVyDQpyYXRlcy5sb25nICU8PiUgbXV0YXRlKHR5cGU9cmVjb2RlX2ZhY3Rvcih0eXBlLCByYXRlLmRhaWx5PSdEYWlseScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhdGUudXBwZXI9J1VwcGVyIGJvdW5kJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmF0ZS5sb3dlciA9ICdMb3dlciBib3VuZCcpKSANCiNWaWV3KHJhdGVzLmxvbmcpIA0KDQpwbG90X3JhdGVzIDwtIHJhdGVzLmxvbmcgJT4lIGZpbHRlcihjb3VudHJ5ID09ICJXb3JsZCIpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IGNvdW50LCBjb2xvciA9IHR5cGUpKSArIA0KICBnZW9tX2xpbmUoKSArDQogIGxhYnModGl0bGUgPSAiV29ybGQgRGVhdGggUmF0ZSAoJSkiKSArDQogIHhsYWIoIiIpICsgeWxhYigiRGVhdGggUmF0ZSAoJSkiKQ0KDQpwbG90X3JhdGVzDQoNCmdseS5yYXRlcyA8LSBnZ3Bsb3RseShwbG90X3JhdGVzKQ0KZ2x5LnJhdGVzDQpgYGANCg0KYGBge3J9DQojIyByYW5raW5nIGJ5IGNvbmZpcm1lZCBjYXNlcw0KZGF0YS5sYXRlc3QuYWxsIDwtIGRhdGEgJT4lIGZpbHRlcihkYXRlID09IG1heChkYXRlKSkgJT4lDQogIHNlbGVjdChjb3VudHJ5LCBkYXRlLGNvbmZpcm1lZCwgbmV3LmNvbmZpcm1lZCwgY3VycmVudC5jb25maXJtZWQsDQogICAgICAgICByZWNvdmVyZWQsIGRlYXRocywgbmV3LmRlYXRocywgZGVhdGgucmF0ZT1yYXRlLmxvd2VyKSAlPiUNCiAgbXV0YXRlKHJhbmtpbmcgPSBkZW5zZV9yYW5rKGRlc2MoY29uZmlybWVkKSkpICU+JQ0KICBhcnJhbmdlKHJhbmtpbmcpDQojVmlldyhkYXRhLmxhdGVzdC5hbGwpDQoNCmsgPC0gMjANCiMjIHRvcCAyMCBjb3VudHJpZXM6IDIxIGluY2wuICdXb3JsZCcNCnRvcC5jb3VudHJpZXMgPC0gZGF0YS5sYXRlc3QuYWxsICU+JSBmaWx0ZXIocmFua2luZyA8PSBrICsgMSkgJT4lDQogIGFycmFuZ2UocmFua2luZykgJT4lIHB1bGwoY291bnRyeSkgJT4lIGFzLmNoYXJhY3RlcigpDQp0b3AuY291bnRyaWVzICU+JSBzZXRkaWZmKCdXb3JsZCcpICU+JSBwcmludCgpDQpgYGANCg0KDQpgYGB7cn0NCmRmIDwtIGRhdGEubG9uZyAlPiUgZmlsdGVyKGNvdW50cnkgJWluJSB0b3AuY291bnRyaWVzKSAlPiUNCiAgbXV0YXRlKGNvdW50cnk9Y291bnRyeSAlPiUgZmFjdG9yKGxldmVscz1jKHRvcC5jb3VudHJpZXMpKSkgJT4lIA0KICBmaWx0ZXIoY291bnRyeSAhPSAnV29ybGQnICYgdHlwZSAhPSAnVG90YWwgQ29uZmlybWVkJykgJT4lDQogIGdncGxvdChhZXMoeD1kYXRlLCB5PWNvdW50LCBjb2xvcj10eXBlKSkgKw0KICBnZW9tX2xpbmUoKSsNCiAgI2dlb21fYXJlYShhbHBoYT0wLjUpICsNCiMgeGxhYignJykgKyB5bGFiKCcnKSArDQogIGxhYnModGl0bGU9cGFzdGUwKCdOdW1iZXJzIG9mIENPVklELTE5IENhc2VzIGluIFRvcCAyMCBDb3VudHJpZXMgLSAnLA0KICAgICAgICAgICAgICAgICAgICBtYXguZGF0ZS50eHQpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygncmVkJywgJ2dyZWVuJywgJ2JsYWNrJykpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uPSdib3R0b20nLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTIpLA0KICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQua2V5LnNpemU9dW5pdCgwLjQsICdjbScpLA0KICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMiksDQogICAgICAgIHN0cmlwLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiksDQogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMiksDQogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpICsNCiAgZmFjZXRfd3JhcCh+Y291bnRyeSwgbmNvbD00LCBzY2FsZXM9J2ZyZWVfeScpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSdsb2cxMCcpDQpkZg0KYGBgDQoNCmBgYHtyfQ0KZGF0YS5sYXRlc3QgPC0gZGF0YS5sYXRlc3QuYWxsICU+JSBmaWx0ZXIoIWlzLm5hKGNvdW50cnkpKSAlPiUNCiAgbXV0YXRlKGNvdW50cnk9aWZlbHNlKHJhbmtpbmcgPD0gayArIDEsIGFzLmNoYXJhY3Rlcihjb3VudHJ5KSwgJ090aGVycycpKSAlPiUNCiAgbXV0YXRlKGNvdW50cnk9Y291bnRyeSAlPiUgZmFjdG9yKGxldmVscz1jKHRvcC5jb3VudHJpZXMsICdPdGhlcnMnKSkpDQpkYXRhLmxhdGVzdCAlPD4lIGdyb3VwX2J5KGNvdW50cnkpICU+JQ0KICBzdW1tYXJpc2UoY29uZmlybWVkPXN1bShjb25maXJtZWQpLCBuZXcuY29uZmlybWVkPXN1bShuZXcuY29uZmlybWVkKSwNCiAgICAgICAgICAgIGN1cnJlbnQuY29uZmlybWVkPXN1bShjdXJyZW50LmNvbmZpcm1lZCksDQogICAgICAgICAgICByZWNvdmVyZWQ9c3VtKHJlY292ZXJlZCksIGRlYXRocz1zdW0oZGVhdGhzKSwgbmV3LmRlYXRocz1zdW0obmV3LmRlYXRocykpICU+JQ0KICBtdXRhdGUoZGVhdGgucmF0ZT0oMTAwICogZGVhdGhzL2NvbmZpcm1lZCkgJT4lIHJvdW5kKDEpKSANCmRhdGEubGF0ZXN0DQpkYXRhLmxhdGVzdCAlPD4lIHNlbGVjdChjKGNvdW50cnksIGNvbmZpcm1lZCwgZGVhdGhzLCBkZWF0aC5yYXRlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcuY29uZmlybWVkLCBuZXcuZGVhdGhzLCBjdXJyZW50LmNvbmZpcm1lZCxyZWNvdmVyZWQpKSAlPiUNCiAgbXV0YXRlKHJlY292ZXIucmF0ZT0oMTAwICogcmVjb3ZlcmVkL2NvbmZpcm1lZCkgJT4lIHJvdW5kKDEpKQ0KZGF0YS5sYXRlc3QNCm1vc3Rjb25maXJtIDwtIGRhdGEubGF0ZXN0ICU+JSBzZWxlY3QoYyhjb3VudHJ5LGNvbmZpcm1lZCkpICU+JSBmaWx0ZXIoY291bnRyeT09IldvcmxkIikNCm1vc3RyZWNvdmVyIDwtIGRhdGEubGF0ZXN0ICU+JSBzZWxlY3QoYyhjb3VudHJ5LHJlY292ZXJlZCkpICU+JSBmaWx0ZXIoY291bnRyeT09IldvcmxkIikNCm1vc3RkZWF0aCA8LSBkYXRhLmxhdGVzdCAlPiUgc2VsZWN0KGMoY291bnRyeSxkZWF0aHMpKSAlPiUgZmlsdGVyKGNvdW50cnk9PSJXb3JsZCIpDQoNCmRmX3BvcCA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBwb3B1bGF0aW9uICIpKQ0KZGZfcG9wIDwtIGFzLmRhdGEuZnJhbWUoZGZfcG9wKQ0KZGZfcG9wIDwtIHJlbmFtZShkZl9wb3AsImNvdW50cnkiPSJDb3VudHJ5IikNCg0KIyBBZGQgV29ybGQgUG9wdWxhdGlvbg0Kd29ybGRfcG9wIDwtIHN1bShkZl9wb3AkYFBvcHVsYXRpb24gKDIwMjApYCkNCmRmX3BvcFtucm93KGRmX3BvcCkgKyAxLF0gPSBjKCJXb3JsZCIsIHdvcmxkX3BvcCkNCg0KIyBBZGQgT3RoZXIgQ291bnRyaWVzIFBvcHVsYXRpb24NCnRvcF9wb3AgPC0gZmlsdGVyKGRmX3BvcCwgZGZfcG9wJGNvdW50cnkgJWluJSB0b3AuY291bnRyaWVzICYgZGZfcG9wJGNvdW50cnkgIT0gIldvcmxkIikNCnRvcF9wb3AgPC0gc3VtKHRvcF9wb3AkYFBvcHVsYXRpb24gKDIwMjApYCAlPiUgYXMubnVtZXJpYygpKQ0Kb3RoZXJzX3BvcCA8LSAod29ybGRfcG9wIC0gdG9wX3BvcCkgDQpkZl9wb3BbbnJvdyhkZl9wb3ApICsgMSxdID0gYygiT3RoZXJzIiwgb3RoZXJzX3BvcCkNCiNWaWV3KGRmX3BvcCkNCg0KZGF0YS5sYXRlc3QgPC0gbWVyZ2UoeCA9IGRhdGEubGF0ZXN0LCB5ID0gZGZfcG9wLCBieSA9ICJjb3VudHJ5IiwgYWxsLnggPSBUUlVFKSANCmRhdGEubGF0ZXN0DQpkYXRhLmxhdGVzdCA8LSByZW5hbWUoZGF0YS5sYXRlc3QsInBvcHVsYXRpb24iID0gIlBvcHVsYXRpb24gKDIwMjApIikNCmRhdGEubGF0ZXN0JHBvcHVsYXRpb24gPC0gZGF0YS5sYXRlc3QkcG9wdWxhdGlvbiAlPiUgYXMubnVtZXJpYygpDQpkYXRhLmxhdGVzdCAgPC0gZGF0YS5sYXRlc3QgJT4lDQogIHNlbGVjdChjKGNvdW50cnksIGNvbmZpcm1lZCwgZGVhdGhzLCBkZWF0aC5yYXRlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcuY29uZmlybWVkLCBuZXcuZGVhdGhzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50LmNvbmZpcm1lZCwgcmVjb3ZlcmVkLCByZWNvdmVyLnJhdGUsIHBvcHVsYXRpb24pKSAlPiUNCiAgbXV0YXRlKGNvbmZpcm0ucmF0ZSA9ICgxMDAgKiBjb25maXJtZWQgLyBwb3B1bGF0aW9uKSAlPiUgcm91bmQoMSkpDQpkYXRhLmxhdGVzdA0KYGBgDQoNCmBgYHtyfQ0KIyMgJSBvZiBkZWF0aA0KZGF0YS5sYXRlc3QgJT4lIG11dGF0ZShkZWF0aC5yYXRlPWRlYXRoLnJhdGUgJT4lIGZvcm1hdChuc21hbGw9MSkgJT4lIHBhc3RlMCgnJScpKQ0KDQojIyBjb252ZXJ0IGZyb20gd2lkZSB0byBsb25nIGZvcm1hdCwgZm9yIGRyYXdpbmcgYXJlYSBwbG90cw0KZGF0YS5sYXRlc3QubG9uZyA8LSBkYXRhLmxhdGVzdCAlPiUgZmlsdGVyKGNvdW50cnkhPSdXb3JsZCcpICU+JQ0KICBnYXRoZXIoa2V5PXR5cGUsIHZhbHVlPWNvdW50LCAtY291bnRyeSkNCiMjIHNldCBmYWN0b3IgbGV2ZWxzIHRvIHNob3cgdGhlbSB3aXRoIHByb3BlciB0ZXh0IGFuZCBpbiBhIGRlc2lyYWJsZSBvcmRlcg0KZGF0YS5sYXRlc3QubG9uZyAlPD4lIG11dGF0ZSh0eXBlPXJlY29kZV9mYWN0b3IodHlwZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpcm1lZD0nVG90YWwgQ29uZmlybWVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlYXRocz0nVG90YWwgRGVhdGhzJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlYXRoLnJhdGU9J0RlYXRoIFJhdGUgKCUpJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldy5jb25maXJtZWQ9J05ldyBDb25maXJtZWQgKGNvbXBhcmVkIHdpdGggb25lIGRheSBiZWZvcmUpJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldy5kZWF0aHM9J05ldyBEZWF0aHMgKGNvbXBhcmVkIHdpdGggb25lIGRheSBiZWZvcmUpJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnQuY29uZmlybWVkPSdDdXJyZW50IENvbmZpcm1lZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNvdmVyLnJhdGUgPSAnUmVjb3ZlcmVkIFJhdGUoJSknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlybS5yYXRlID0gJ0NvbmZpcm1lZCBSYXRlKCUpJykpDQojVmlldyhkYXRhLmxhdGVzdC5sb25nKQ0KZGF0YS5vbmUuZGVtIDwtIGZpbHRlcihkYXRhLmxhdGVzdC5sb25nLHR5cGU9PSdUb3RhbCBDb25maXJtZWQnDQogICAgICAgICAgICAgICAgICAgICAgIHwgdHlwZT09J1RvdGFsIERlYXRocycNCiAgICAgICAgICAgICAgICAgICAgICAgfCB0eXBlPT0nQ3VycmVudCBDb25maXJtZWQnKQ0KZGF0YS50d28uZGVtIDwtIGZpbHRlcihkYXRhLmxhdGVzdC5sb25nLHR5cGU9PSdEZWF0aCBSYXRlICglKScNCiAgICAgICAgICAgICAgICAgICAgICMgIHwgdHlwZT09J05ldyBDb25maXJtZWQgKGNvbXBhcmVkIHdpdGggb25lIGRheSBiZWZvcmUpJw0KICAgICAgICAgICAgICAgICAgICAjICAgfCB0eXBlPT0nTmV3IERlYXRocyAoY29tcGFyZWQgd2l0aCBvbmUgZGF5IGJlZm9yZSknDQogICAgICAgICAgICAgICAgICAgICAgIHwgdHlwZT09J1JlY292ZXJlZCBSYXRlKCUpJw0KICAgICAgICAgICAgICAgICAgICAgICB8IHR5cGU9PSdDb25maXJtZWQgUmF0ZSglKScpDQpkYXRhLnR3by5kZW0NCmBgYA0KDQpgYGB7cn0NCiMjIGJhciBjaGFydA0KZGF0YS5vbmUuZGVtICU+JSBnZ3Bsb3QoYWVzKHg9Y291bnRyeSwgeT1jb3VudCwgZmlsbD1jb3VudHJ5LCBncm91cD1jb3VudHJ5KSkgKw0KICBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1jb3VudCwgeT1jb3VudCksIHNpemU9Mywgdmp1c3Q9MCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJycpICsNCiAgbGFicyh0aXRsZT1wYXN0ZTAoJ1RvcCAyMCBDb3VudHJpZXMgd2l0aCBNb3N0IENvbmZpcm1lZCBDYXNlcyAtICcsIG1heC5kYXRlLnR4dCkpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lPSdDb3VudHJ5JywgbGFiZWxzPWFlcyhjb3VudCkpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSdub25lJywNCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMyksDQogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkgKw0KICBmYWNldF93cmFwKH50eXBlLCBuY29sPTEsIHNjYWxlcz0nZnJlZV95JykNCmBgYA0KDQpgYGB7cn0NCmRhdGEudHdvLmRlbSRmYWNldCA8LSBmYWN0b3IoZGF0YS50d28uZGVtJHR5cGUsIGxldmVscyA9IGMoJ0NvbmZpcm1lZCBSYXRlKCUpJywgJ1JlY292ZXJlZCBSYXRlKCUpJywnRGVhdGggUmF0ZSAoJSknKSkNCmRhdGEudHdvLmRlbSAlPiUgDQogIGdncGxvdChhZXMoeD1jb3VudHJ5LCB5PWNvdW50LCBmaWxsPWNvdW50cnksIGdyb3VwPWNvdW50cnkpKSArDQogIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPWNvdW50LCB5PWNvdW50KSwgc2l6ZT00LCB2anVzdD0wKSArDQogIHhsYWIoJycpICsgeWxhYignJykgKw0KICBsYWJzKHRpdGxlPXBhc3RlMCgnVG9wIDIwIENvdW50cmllcyB3aXRoIE1vc3QgQ29uZmlybWVkIENhc2VzIC0gJywgbWF4LmRhdGUudHh0KSkgKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWU9J0NvdW50cnknLCBsYWJlbHM9YWVzKGNvdW50KSkgKw0KICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb249J25vbmUnLA0KICAgICAgICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEzKSwNCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEwKSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTAsYW5nbGU9NDUsIGhqdXN0PTEpKSArDQogIGZhY2V0X3dyYXAofmZhY2V0LCBuY29sPTEsIHNjYWxlcz0nZnJlZV95JykNCmBgYA0KDQpgYGB7cn0NCiMjR0RQDQpkZl9nZHAyMDE5IDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGdkcDE5IikpDQpkZl9nZHAyMDE5IDwtIGFzLmRhdGEuZnJhbWUoZGZfZ2RwMjAxOSkNCmRmX2dkcDIwMTkNCmBgYA0KDQpgYGB7cn0NCiNoZWFsdGhyYW5raW5nIGRhdGENCmRmX2hlYWx0IDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGhlYWx0aHJhbmtpbmciKSkNCmRmX2hlYWx0IDwtIGFzLmRhdGEuZnJhbWUoZGZfaGVhbHQpDQpkZl9oZWFsdCA8LSBzZWxlY3QoZGZfaGVhbHQsYygiY291bnRyeSIsImhlYWx0aENhcmVJbmRleCIpKQ0KI1ZpZXcoZGZfaGVhbHQpDQpgYGANCg0KYGBge3J9DQojVG9wMjBQb3JuaHViIGRhdGENCiNkZl9wb3JuaHViIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIFBvcm5odWIiKSkNCiNkZl9wb3JuaHViIDwtIGFzLmRhdGEuZnJhbWUoZGZfcG9ybmh1YikNCiNkZl9wb3JuaHViDQpgYGANCg0KYGBge3J9DQojIHRlbXAgZGF0YQ0KZGZfdGVtcCA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSB3b3JsZF90ZW1wIikpDQpkZl90ZW1wIDwtIGFzLmRhdGEuZnJhbWUoZGZfdGVtcCkgDQpkZl90ZW1wJENvdW50cnlbZGZfdGVtcCRDb3VudHJ5ID09ICJVbml0ZWQgU3RhdGVzIl0gPC0gIlVTIg0KDQpkZl9jaXR5IDwtIHNlbGVjdChkZl90ZW1wLGMoIkNvdW50cnkiLCJDaXR5IikpICU+JQ0KICByZW5hbWUoY291bnRyeT1Db3VudHJ5KSAlPiUgDQogIHJlbmFtZShjaXR5PUNpdHkpDQoNCm51bW9mY2l0eSA8LSBhZ2dyZWdhdGUoY2l0eSB+IGNvdW50cnksIGRhdGEgPSBkZl9jaXR5LCBsZW5ndGgpDQoNCiNjbGVhbiBkYXRhDQpkZl90ZW1wIDwtIHNlbGVjdChkZl90ZW1wLGMoIkNvdW50cnkiLCJBdmdfWWVhciIpKSAlPiUNCiAgcmVuYW1lKGNvdW50cnk9Q291bnRyeSkNCiNWaWV3KGRmX3RlbXApDQoNCiNkZl90ZW1wIDwtIGRhdGEuZnJhbWUoY291bnRyeT1kZl90ZW1wWywxXSxhdmc9cm93TWVhbnMoZGZfdGVtcFssLTFdKSkNCmRmX3RlbXAgPC0gZGZfdGVtcCAlPD4lIGdyb3VwX2J5KGNvdW50cnkpICU+JSBzdW1tYXJpc2UoYXZnX3RlbXAgPSBtZWFuKEF2Z19ZZWFyLG5hLnJtID0gVFJVRSklPiUgcm91bmQoMSkpDQpkZl90ZW1wDQpgYGANCg0KYGBge3J9DQojI3RlbXAgYmFyDQpkZl90ZW1wLmFsbCA8LSBkZl90ZW1wICU+JSBtZXJnZShkYXRhLmxhdGVzdC5hbGwpDQojVmlldyhkZl90ZW1wLmFsbCkNCmRmX3RlbXBfdG9wLmFsbCA8LSBkZl90ZW1wLmFsbCAlPiUgZmlsdGVyKGNvdW50cnkgJWluJSB0b3AuY291bnRyaWVzKSAlPiUNCiAgbXV0YXRlKHJhbmtpbmcgPSByYW5raW5nIC0gMSkgJT4lDQogIGFycmFuZ2UocmFua2luZykNCiNWaWV3KGRmX3RlbXBfdG9wLmFsbCkNCmdfdGVtcF90b3AgPC0gZGZfdGVtcF90b3AuYWxsICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGNvdW50cnksIHJhbmtpbmcpLCB5ID0gYXZnX3RlbXAsIGZpbGwgPSBhdmdfdGVtcCkpICsNCiAgbGFicyh0aXRsZT1wYXN0ZTAoIlRlbXBlcmF0dXJlIGluIFRvcCAgMjAgY291bnRyaWVzIiksIHN1YnRpdGxlID0gIkF2ZXJhZ2UgVGVtcGVyYXR1cmUgaW4gVG9wIDIwIGNvdW50cmllcyB3aXRoIG1vc3QgY29uZmlybWVkIGNhc2VzICjCsEMpICgyMDIwKSIpICsNCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gIiM5M0RCRkYiLCBoaWdoID0gIiNGRjc3NzEiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWw9YXZnX3RlbXAsIHk9YXZnX3RlbXApLCBzaXplPTQsIHZqdXN0PS0wLjUpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKw0KICB0aGVtZSgNCiAgICAgICAgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSdub25lJywNCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBoanVzdCA9IDAuNSksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBoanVzdCA9IDAuNSksDQogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemUgPSA5LCBhbmdsZT00NSwgaGp1c3Q9MSkpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0gIkNvdW50cnkiKSArDQogIHNjYWxlX3lfZGlzY3JldGUobmFtZSA9ICJBdmVyYWdlIFRlbXBlcmF0dXJlIikNCg0KICAgICAgICAgICAjbGFicyh0aXRsZSA9ICJUZW1wZXJhdHVyZSBpbiBUb3AgIDIwIGNvdW50cmllcyIsIHN1YnRpdGxlID0gIlRlbXBlcmF0dXJlIGluIFRvcCAyMCBjb3VudHJpZXMgd2l0aCBtb3N0IGNvbmZpcm1lZCBjYXNlcyAowrBDKSIpDQogICAgICAgICANCiNnX3RlbXBfdG9wICAgICAgICAgDQpnX3RlbXBfdG9wIA0KYGBgDQoNCmBgYHtyfQ0KI2RhdGEubGF0ZXN0LmFsbA0KbGF0LmxvbmcgPC0gcmVuYW1lKGRmX2NvbmYsICJjb3VudHJ5IiA9ICJDb3VudHJ5LlJlZ2lvbiIsICJjaXR5IiA9ICJQcm92aW5jZS5TdGF0ZSIpICU+JSANCiAgc2VsZWN0KCJjb3VudHJ5IiwgIkxhdCIsICJMb25nIikgJT4lIA0KICBtZXJnZShkZl90ZW1wLmFsbFtjKCJjb3VudHJ5IiwiY29uZmlybWVkIiwgInJlY292ZXJlZCIsICJkZWF0aHMiLCAiYXZnX3RlbXAiLCAicmFua2luZyIpXSwgYnkgPSAiY291bnRyeSIpICU+JQ0KICBkaXN0aW5jdChjb3VudHJ5LCAua2VlcF9hbGwgPSBUUlVFKSAlPiUNCiAgbXV0YXRlKHJhbmtpbmcgPSByYW5raW5nIC0gMSkgJT4lDQogIGFycmFuZ2UocmFua2luZykNCiNWaWV3KGxhdC5sb25nKQ0KYGBgDQoNCmBgYHtyfQ0KbGFiZWxfd29ybGQgPC0gbGF0LmxvbmcgDQpsYWJlbF93b3JsZCRhdmdfdGVtcCA8LSBhcy5udW1lcmljKGxhYmVsX3dvcmxkWywgbmFtZXMobGFiZWxfd29ybGQpICVpbiUgYygiYXZnX3RlbXAiKV0pDQpsYWJlbF93b3JsZCA8LSBsYWJlbF93b3JsZCAlPiUgIA0KICBtdXRhdGUodHh0PXBhc3RlMCgnPGI+JyxyYW5raW5nLCAnPC9iPicsDQogICAgICAgICAgICAgICAgICAgICc8YnIvPicsJzxiPicsY291bnRyeSwgJzwvYj4nLA0KICAgICAgICAgICAgICAgICAgICAnPGJyLz4nLCAiVGVtcGVyYXR1cmU6ICAiLGF2Z190ZW1wLCAnIMKwQycsDQogICAgICAgICAgICAgICAgICAgICc8YnIvPicsICJDb25maXJtZWQ6ICAiLCBjb25maXJtZWQsIA0KICAgICAgICAgICAgICAgICAgICAnPGJyLz4nLCAiRGVhdGhzOiAiLCBkZWF0aHMsDQogICAgICAgICAgICAgICAgICAgICc8YnIvPicsICJSZWNvdmVyZWQ6ICIsIHJlY292ZXJlZA0KICAgICAgICAgICAgICAgICAgICApKSANCg0KbGFiZWxfd29ybGQkdHh0IDwtIGxhYmVsX3dvcmxkJHR4dCAlPiUgbGFwcGx5KGh0bWx0b29sczo6SFRNTCkNCmxhYmVsX3dvcmxkIA0KDQpsYWJlbF90b3AgPC0gbGFiZWxfd29ybGQgJT4lIGZpbHRlcihyYW5raW5nIDwgMjEpDQpsYWJlbF90b3ANCmBgYA0KDQoNCmBgYHtyfQ0KIyBUZW1wZXJhdHVyZSBNYXANCndwYWwgPC0gY29sb3JOdW1lcmljKCJZbE9yUmQiLCBsYWJlbF93b3JsZCRhdmdfdGVtcCwgbiA9IDQpDQoNCnRvcEljb24gPC0gbWFrZUljb24oInN0YXIucG5nIiwNCiAgI2ljb25VcmwgPSAiaHR0cHM6Ly9zdGF0aWMudmVjdGVlenkuY29tL3N5c3RlbS9yZXNvdXJjZXMvcHJldmlld3MvMDAxLzE4OS8wNjMvbm9uXzJ4L3N0YXItcm91bmRlZC1wbmcucG5nIiwNCiAgaWNvbldpZHRoID0gMTAsIGljb25IZWlnaHQgPSAxMA0KICAjaWNvbkFuY2hvclggPSAyMCwgaWNvbkFuY2hvclkgPSAyMA0KICANCikNCg0KbGFiZWxfd29ybGQgPC0gbGFiZWxfd29ybGQgJT4lIGZpbHRlcihyYW5raW5nID4gMjApIA0KICANCm0gPC0gbGVhZmxldCh3aWR0aD0xMjAwLCBoZWlnaHQ9ODAwKSAlPiUgYWRkVGlsZXMoKSAgDQptICU8PiUgIGFkZENpcmNsZU1hcmtlcnMobGFiZWxfd29ybGQkTG9uZywgbGFiZWxfd29ybGQkTGF0LA0KICAgICAgICAgICAgICAgICAgICAgICAgIyByYWRpdXM9Mitsb2cyKHgkY29uZmlybWVkKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHJhZGl1cz0xMCwjKmxvZzIobS53b3JsZCRhdmcudGVtcCksDQogICAgICAgICAgICAgICAgICAgICAgICBzdHJva2U9RiwNCiAgICAgICAgICAgICAgICAgICAgICAgICNjb2xvcj0ncmVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gd3BhbChsYWJlbF93b3JsZCRhdmdfdGVtcCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHk9MC41LA0KICAgICAgICAgICAgICAgICAgICAgICAgI3BvcHVwPWxhYmVsLnRvcCR0eHQNCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSBsYWJlbF93b3JsZCR0eHQsDQogICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9ICJXb3JsZCINCiAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lDQogIA0KICBhZGRDaXJjbGVNYXJrZXJzKGxhYmVsX3RvcCRMb25nLCBsYWJlbF90b3AkTGF0LA0KICAgICAgICAgICAgICAgICAgICAgICAgIyByYWRpdXM9Mitsb2cyKHgkY29uZmlybWVkKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHJhZGl1cz0xMCwjKmxvZzIobS53b3JsZCRhdmcudGVtcCksDQogICAgICAgICAgICAgICAgICAgICAgICBzdHJva2U9RiwNCiAgICAgICAgICAgICAgICAgICAgICAgICNjb2xvcj0ncmVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gd3BhbChsYWJlbF90b3AkYXZnX3RlbXApLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5PTAuNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICNwb3B1cD1sYWJlbC50b3AkdHh0DQogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0gbGFiZWxfdG9wJHR4dCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gIlRvcCAyMCBDb3VudHJpZXMiDQogICAgICAgICAgICAgICAgICAgICAgICApICU+JQ0KICANCiAgYWRkTGFiZWxPbmx5TWFya2VycyhsYWJlbF90b3AkTG9uZywgbGFiZWxfdG9wJExhdCwgbGFiZWwgPSBsYWJlbF90b3AkcmFua2luZywNCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMobm9IaWRlID0gVFJVRSwgdGV4dE9ubHkgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImhlYWQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2Zmc2V0ID0gYyg1LDQpKSwNCiAgICAgICAgICAgICAgICAgICAgICBncm91cCA9ICJUb3AgMjAgQ291bnRyaWVzIikgJT4lDQogIA0KICBhZGRMZWdlbmQoImJvdHRvbXJpZ2h0IiwgcGFsID0gd3BhbCwgdmFsdWVzID0gbGFiZWxfd29ybGQkYXZnX3RlbXAsIG9wYWNpdHkgPSAxLA0KICAgICAgICAgICAgbGFiRm9ybWF0ID0gbGFiZWxGb3JtYXQoc3VmZml4ID0gIiDCsEMiKSwNCiAgICAgICAgICAgIHRpdGxlID0gIlRlbXBlcmF0dXJlIikgJT4lIA0KICANCiAgYWRkTGF5ZXJzQ29udHJvbCgNCiAgICAjYmFzZUdyb3VwcyA9IGMoIk9TTSAoZGVmYXVsdCkiLCAiVG9uZXIiLCAiVG9uZXIgTGl0ZSIpLA0KICAgIG92ZXJsYXlHcm91cHMgPSBjKCJUb3AgMjAgQ291bnRyaWVzIiwgIldvcmxkIiksDQogICAgb3B0aW9ucyA9IGxheWVyc0NvbnRyb2xPcHRpb25zKGNvbGxhcHNlZCA9IEZBTFNFKQ0KICApDQptDQpgYGANCg0KYGBge3J9DQpnZHAudG9wMjAgPC0gZGZfZ2RwMjAxOSAlPiUNCiAgc2VsZWN0KGMoInJhbmsiLCAiY291bnRyeSIsICJHRFAgKG1pbGxpb25zIG9mIFVTIGRvbGxhcnMpIikpICU+JQ0KICBtZXJnZShkYXRhLmxhdGVzdC5hbGwgJT4lIA0KICAgICAgICAgIHNlbGVjdChjb3VudHJ5LCByYW5raW5nLCBjb25maXJtZWQsIHJlY292ZXJlZCwgZGVhdGhzKSAlPiUgDQogICAgICAgICAgZmlsdGVyKGNvdW50cnkgJWluJSB0b3AuY291bnRyaWVzICYgY291bnRyeSAhPSAiV29ybGQiKSwgYnkgPSAiY291bnRyeSIpICU+JQ0KICBhcnJhbmdlKHJhbmtpbmcpICU+JSANCiAgbXV0YXRlKHJhbmtpbmcgPSByYW5raW5nIC0gMSkgDQpnZHAudG9wMjAgJTw+JSByZW5hbWUoIkdEUCIgPSAiR0RQIChtaWxsaW9ucyBvZiBVUyBkb2xsYXJzKSIpDQpnZHAudG9wMjANCg0KZyA8LSBnZ3Bsb3QoZ2RwLnRvcDIwLCBhZXMoeCA9IEdEUCwgeSA9IHJlb3JkZXIoY291bnRyeSwgLXJhbmtpbmcpKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShzdGF0ID0gImlkZW50aXR5IiwgYWVzKGZpbGwgPSBHRFApKSsgDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoIkdEUCIsIGxvdyA9ICIjRkY0MDM4IiwgaGlnaCA9ICIjNTBFOTUyIikgKyANCiAgbGFicyh0aXRsZT1wYXN0ZTAoIkdEUCAgb2YgVG9wIDIwIENvdW50cmllcyBpbiAyMDE5IChtaWxsaW9ucyBvZiBVUyBkb2xsYXJzKSIpKSArDQogIGdlb21fdGV4dChhZXMobGFiZWw9R0RQLCB4ID0gR0RQKSwgc2l6ZT0zLjUsIGhqdXN0PS0wLjIpICsNCiAgeGxhYigiR0RQIChtaWxsaW9ucyBvZiBVUyBkb2xsYXJzKSIpICsNCiAgeWxhYigiIikgKw0KICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKQ0KZw0KDQpnbHkudG9wLmdkcCA8LSBnZ3Bsb3RseShnKQ0KZ2x5LnRvcC5nZHANCmBgYA0KDQpgYGB7cn0NCiMgUG9ybmh1Yg0KZGZfcG9ybmh1YiA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBwb3JuaHViIikpDQpkZl9wb3JuaHViIDwtIGFzLmRhdGEuZnJhbWUoZGZfcG9ybmh1YikNCmRmX3Bvcm5odWINCmBgYA0KDQoNCmBgYHtyfQ0KIyBTYXJzDQpkZl9zYXJzIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIHNhcnNfMjAwMyIpKQ0KZGZfc2FycyA8LSBhcy5kYXRhLmZyYW1lKGRmX3NhcnMpDQojVmlldyhkZl9zYXJzKQ0KDQpkYXRlcy5zIDwtIGRmX3NhcnNbLDFdJT4lIG1keSgpDQpyYW5nZShkYXRlcy5zKQ0KbWluLmRhdGUucyA8LSBtaW4oZGF0ZXMucykNCm1heC5kYXRlLnMgPC0gbWF4KGRhdGVzLnMpDQptaW4uZGF0ZS50eHQucyA8LSBtaW4uZGF0ZS5zICU+JSBmb3JtYXQoJyVkICViICVZJykNCm1heC5kYXRlLnR4dC5zIDwtIG1heC5kYXRlLnMgJT4lIGZvcm1hdCgnJWQgJWIgJVknKQ0KZGF5MS5zYXJzIDwtIG1pbi5kYXRlLnMNCmBgYA0KDQpgYGB7cn0NCiMgY2xlYW4gZGF0YSBTYXJzIA0KZGF0YS5zYXJzIDwtIGRmX3NhcnMgJT4lIHJlbmFtZShjKCJkYXRlIiA9ICJEYXRlIiwgImNvbmZpcm1lZCIgPSAiQ3VtdWxhdGl2ZV9udW1iZXIiICAsImRlYXRocyIgPSAiTnVtYmVyX2RlYXRocyIsICJyZWNvdmVyZWQiID0gIk51bWJlcl9yZWNvdmVyZWQiKSkgJT4lDQogIG11dGF0ZShkYXRlID0gZGF0ZSAlPiUgbWR5KCkpICU+JQ0KICBncm91cF9ieShjb3VudHJ5LCBkYXRlKSAlPiUgYXMuZGF0YS5mcmFtZSgpIA0KDQojIEFkZCBXb3JsZCdzIFNhcnMgY2FzZXMgDQp3b3JsZC5zYXJzIDwtIGRhdGEuc2FycyAlPiUgZ3JvdXBfYnkoZGF0ZSkgJT4lIA0KICBzdW1tYXJpc2UoY291bnRyeT0nV29ybGQnLA0KICAgICAgICAgICAgY29uZmlybWVkID0gc3VtKGNvbmZpcm1lZCwgbmEucm09VCksDQogICAgICAgICAgICBkZWF0aHMgPSBzdW0oZGVhdGhzLCBuYS5ybT1UKSwNCiAgICAgICAgICAgIHJlY292ZXJlZCA9IHN1bShyZWNvdmVyZWQsIG5hLnJtPVQpKQ0KDQpkYXRhLnNhcnMgJTw+JSByYmluZCh3b3JsZC5zYXJzKQ0KZGF0YS5zYXJzICU8PiUgbXV0YXRlKGN1cnJlbnQuY29uZmlybWVkID0gY29uZmlybWVkIC0gZGVhdGhzIC0gcmVjb3ZlcmVkKQ0KI1ZpZXcod29ybGQuc2FycykgDQpkYXRhLnNhcnMNCmBgYA0KDQoNCmBgYHtyfQ0KI3JhdGUNCmRhdGEuc2FycyAlPD4lIGFycmFuZ2UoY291bnRyeSwgZGF0ZSkNCm4gPC0gbnJvdyhkYXRhLnNhcnMpDQpkYXkxLnNhcnMgPC0gbWluKGRhdGEuc2FycyRkYXRlKQ0KZGF0YS5zYXJzICU8PiUgbXV0YXRlKG5ldy5jb25maXJtZWQgPSBpZmVsc2UoZGF0ZSA9PSBkYXkxLnNhcnMsIE5BLCBjb25maXJtZWQgLSBsYWcoY29uZmlybWVkLCBuPTEpKSwNCiAgICAgICAgICAgICAgICAgbmV3LmRlYXRocyA9IGlmZWxzZShkYXRlID09IGRheTEuc2FycywgTkEsIGRlYXRocyAtIGxhZyhkZWF0aHMsIG49MSkpLA0KICAgICAgICAgICAgICAgICBuZXcucmVjb3ZlcmVkID0gaWZlbHNlKGRhdGUgPT0gZGF5MS5zYXJzLCBOQSwgcmVjb3ZlcmVkIC0gbGFnKHJlY292ZXJlZCwgbj0xKSkpDQpkYXRhLnNhcnMgJTw+JSBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShuZXcuY29uZmlybWVkIDwgMCwgMCwgbmV3LmNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgIG5ldy5kZWF0aHMgPSBpZmVsc2UobmV3LmRlYXRocyA8IDAsIDAsIG5ldy5kZWF0aHMpLA0KICAgICAgICAgICAgICAgICBuZXcucmVjb3ZlcmVkID0gaWZlbHNlKG5ldy5yZWNvdmVyZWQgPCAwLCAwLCBuZXcucmVjb3ZlcmVkKSkNCiMjIGRlYXRoIHJhdGUgYmFzZWQgb24gdG90YWwgZGVhdGhzIGFuZCByZWNvdmVyZWQgY2FzZXMNCmRhdGEuc2FycyAlPD4lIG11dGF0ZShyYXRlLnVwcGVyID0gKDEwMCAqIGRlYXRocyAvIChkZWF0aHMgKyByZWNvdmVyZWQpKSAlPiUgcm91bmQoMSksDQogICAgICAgICAgICAgICAgIHJhdGUudXBwZXIgPSBpZmVsc2UoaXMubmFuKHJhdGUudXBwZXIpLCAwLCByYXRlLnVwcGVyKSkNCg0KIyMgbG93ZXIgYm91bmQ6IGRlYXRoIHJhdGUgYmFzZWQgb24gdG90YWwgY29uZmlybWVkIGNhc2VzDQpkYXRhLnNhcnMgJTw+JSBtdXRhdGUocmF0ZS5sb3dlciA9ICgxMDAgKiBkZWF0aHMgLyBjb25maXJtZWQpICU+JSByb3VuZCgxKSwNCiAgICAgICAgICAgICAgICAgcmF0ZS5sb3dlciA9IGlmZWxzZShpcy5uYW4ocmF0ZS5sb3dlciksIDAsIHJhdGUubG93ZXIpKQ0KDQojIyBkZWF0aCByYXRlIGJhc2VkIG9uIHRoZSBudW1iZXIgb2YgZGVhdGgvcmVjb3ZlcmVkIG9uIGV2ZXJ5IHNpbmdsZSBkYXkNCmRhdGEuc2FycyAlPD4lIG11dGF0ZShyYXRlLmRhaWx5ID0gKDEwMCAqIG5ldy5kZWF0aHMgLyAobmV3LmRlYXRocyArIG5ldy5yZWNvdmVyZWQpKSAlPiUgcm91bmQoMSksDQogICAgICAgICAgICAgICAgIHJhdGUuZGFpbHkgPSBpZmVsc2UoaXMubmFuKHJhdGUuZGFpbHkpLCAwLCByYXRlLmRhaWx5KSkNCg0KI1ZpZXcoZGF0YS5zYXJzKQ0KYGBgDQoNCmBgYHtyfQ0KIyMgY29udmVydCBmcm9tIHdpZGUgdG8gbG9uZyBmb3JtYXQNCmRhdGEuc2Fycy5sb25nIDwtIGRhdGEuc2FycyAlPiUNCiAgc2VsZWN0KGMoY291bnRyeSwgZGF0ZSwgY29uZmlybWVkLCBjdXJyZW50LmNvbmZpcm1lZCwgcmVjb3ZlcmVkLCBkZWF0aHMpKSAlPiUNCiAgZ2F0aGVyKGtleT10eXBlLCB2YWx1ZT1jb3VudCwgLWMoY291bnRyeSwgZGF0ZSkpDQojIyBzZXQgZmFjdG9yIGxldmVscyB0byBzaG93IHRoZW0gaW4gYSBkZXNpcmFibGUgb3JkZXINCmRhdGEuc2Fycy5sb25nICU8PiUgbXV0YXRlKHR5cGU9cmVjb2RlX2ZhY3Rvcih0eXBlLCBjb25maXJtZWQ9J1RvdGFsIENvbmZpcm1lZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnQuY29uZmlybWVkPSdDdXJyZW50IENvbmZpcm1lZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY292ZXJlZD0nUmVjb3ZlcmVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVhdGhzPSdEZWF0aHMnKSkNCiNWaWV3KGRhdGEuc2Fycy5sb25nKQ0KDQojIFdvcmxkIHNhcnMnIGxvbmcgZGF0YSANCndvcmxkLnNhcnMubG9uZyA8LSBkYXRhLnNhcnMubG9uZyAlPiUNCiAgZmlsdGVyKGNvdW50cnkgPT0gIldvcmxkIikNCiNWaWV3KHdvcmxkLnNhcnMubG9uZykNCg0KZyA8LSBnZ3Bsb3Qod29ybGQuc2Fycy5sb25nLCBhZXMoZGF0ZSwgY291bnQsIGNvbG9yID0gdHlwZSkpICsNCiAgZ2VvbV9saW5lKCkrDQogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIENhc2VzIFdvcmxkd2lkZTogU0FScyIpKw0KICB4bGFiKCIiKSsNCiAgeWxhYigiIikNCmcNCg0KZ2x5LmcgPC0gZ2dwbG90bHkoZykNCmdseS5nDQpnbHkucGxvdF93b3JsZC5saW5lDQpgYGANCg0KYGBge3J9DQpkZl9zYXJzX2xhc3RkYXRlIDwtIGRhdGEuc2FycyAlPiUNCiAgZmlsdGVyKGRhdGUgPT0gbWF4LmRhdGUucykNCg0KZGZfc2Fyc19sYXN0ZGF0ZQ0KYGBgDQoNCg0KYGBge3J9DQojIyBDdXJyZW50IENvbmZpcm1lZCBDYXNlcw0KZGF0YS5zYXJzLndvcmxkIDwtIGRhdGEuc2FycyAlPiUgZmlsdGVyKGNvdW50cnk9PSdXb3JsZCcpDQojVmlldyhkYXRhLnNhcnMud29ybGQpDQpuIDwtIG5yb3coZGF0YS5zYXJzLndvcmxkKQ0KI1ZpZXcoZGF0YS5zYXJzLndvcmxkKQ0KcGxvdF9zYXJzLmN1cnJjb25mIDwtIGdncGxvdChkYXRhLnNhcnMud29ybGQsIGFlcyh4PWRhdGUsIHk9Y3VycmVudC5jb25maXJtZWQpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdDdXJyZW50IENvbmZpcm1lZCBDYXNlcycpICsNCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkNCnBsb3Rfc2Fycy5uZXdjb25mIDwtIGdncGxvdChkYXRhLnNhcnMud29ybGQsIGFlcyh4PWRhdGUsIHk9bmV3LmNvbmZpcm1lZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J0RhaWx5IE5ldyBDb25maXJtZWQgQ2FzZXMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQojIyBzaG93IHR3byBwbG90cyBzaWRlIGJ5IHNpZGUNCmdyaWQuYXJyYW5nZShwbG90X3NhcnMuY3VycmNvbmYsIHBsb3Rfc2Fycy5uZXdjb25mLCBuY29sPTIpDQpgYGANCg0KYGBge3J9DQojIyBhIHNjYXR0ZXIgcGxvdCB3aXRoIGEgc21vb3RoZWQgbGluZSBhbmQgdmVydGljYWwgeC1heGlzIGxhYmVscw0KcGxvdF9zYXJzLmFjY2RlYXRocyA8LSBnZ3Bsb3QoZGF0YS5zYXJzLndvcmxkLCBhZXMoeD1kYXRlLCB5PWRlYXRocykpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J0FjY3VtdWxhdGl2ZSBEZWF0aHMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQpwbG90X3NhcnMuYWNjcmVjb3YgPC0gZ2dwbG90KGRhdGEuc2Fycy53b3JsZCwgYWVzKHg9ZGF0ZSwgeT1yZWNvdmVyZWQpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdBY2N1bXVsYXRpdmUgUmVjb3ZlcmVkIENhc2VzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdF9zYXJzLm5ld2RlYXRocyA8LSBnZ3Bsb3QoZGF0YS5zYXJzLndvcmxkLCBhZXMoeD1kYXRlLCB5PW5ldy5kZWF0aHMpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdOZXcgRGVhdGhzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdF9zYXJzLm5ld3JlY292IDwtIGdncGxvdChkYXRhLnNhcnMud29ybGQsIGFlcyh4PWRhdGUsIHk9bmV3LnJlY292ZXJlZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J05ldyBSZWNvdmVyZWQgQ2FzZXMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQojIyBzaG93IGZvdXIgcGxvdHMgdG9nZXRoZXIsIHdpdGggMiBwbG90cyBpbiBlYWNoIHJvdw0KZ3JpZC5hcnJhbmdlKHBsb3Rfc2Fycy5hY2NkZWF0aHMsIHBsb3Rfc2Fycy5hY2NyZWNvdiwgcGxvdF9zYXJzLm5ld2RlYXRocywgcGxvdF9zYXJzLm5ld3JlY292LCBucm93PTIpDQpgYGANCg0KDQpgYGB7cn0NCiNUb3AgMjAgd2l0aCBnZHANCmRhdGEubG9uZ0dEUCA8LSBkZl9nZHAyMDE5ICU+JSBnYXRoZXIoa2V5PXllYXIsIHZhbHVlPUdEUCwgLWMoY291bnRyeSkpDQpkYXRhLnRvcCA8LSBkYXRhLmxhdGVzdCAlPiUgZmlsdGVyKCFjb3VudHJ5ICVpbiUgYygnV29ybGQnLCAnT3RoZXJzJykpDQpkYXRhLnRvcCA8LSBoZWFkKGRhdGEudG9wLDIwKQ0KI1ZpZXcoZGF0YS5sYXRlc3QpDQpkYXRhLmdkcCA8LSBmaWx0ZXIoZGF0YS5sb25nR0RQLHllYXI9PScyMDIwJykNCmRmX3NhcnNfbGFzdGRhdGVfY29uZmlybWVkIDwtIGRmX3NhcnNfbGFzdGRhdGUgJT4lDQogIHNlbGVjdCgiY291bnRyeSIsICJjb25maXJtZWQiKSAlPiUNCiAgcmVuYW1lKHNhcnMgPSAiY29uZmlybWVkIikNCiNWaWV3KGRmX3NhcnNfbGFzdGRhdGVfY29uZmlybWVkKQ0KI21lcmdlDQptZXJnY291bnRyeSA9IGZ1bmN0aW9uKGRhdGExLGRhdGEyKXsNCiAgZGF0YSA8LSBtZXJnZSh4ID0gZGF0YTEsIHkgPSBkYXRhMiwgYnkgPSAiY291bnRyeSIsIGFsbC54ID0gVFJVRSkgDQogIHJldHVybihkYXRhKQ0KfQ0KZGF0YS50b3Aud29ybGQgPC0gbWVyZ2UoeCA9IGRhdGEudG9wLCB5ID0gZGZfZ2RwMjAxOSwgYnkgPSAiY291bnRyeSIsIGFsbC54ID0gVFJVRSkgJT4lIA0KICBzZWxlY3QoLWMoY29kZSxyYW5rLG5ldy5jb25maXJtZWQsbmV3LmRlYXRocyxjdXJyZW50LmNvbmZpcm1lZCxwb3B1bGF0aW9uKSkgJT4lIA0KICByZW5hbWUoR0RQPSJHRFAgKG1pbGxpb25zIG9mIFVTIGRvbGxhcnMpIikNCg0KZGF0YS50b3Aud29ybGQgPC0gbWVyZ2UoeCA9IGRhdGEudG9wLndvcmxkLCB5ID0gZGZfaGVhbHQsIGJ5ID0gImNvdW50cnkiLCBhbGwueCA9IFRSVUUpICU+JQ0KICByZW5hbWUoaGVhbHRoY2FyZT0iaGVhbHRoQ2FyZUluZGV4IikNCiNkYXRhLnRvcC53b3JsZCA8LSBtZXJnY291bnRyeShkYXRhLnRvcC53b3JsZCwgZGZfdGVtcCkNCg0KZGF0YS50b3Aud29ybGQgPC0gbWVyZ2UoeCA9IGRhdGEudG9wLndvcmxkLCB5ID0gZGZfcG9ybmh1YiwgYnkgPSAiY291bnRyeSIsIGFsbC54ID0gVFJVRSkgJT4lDQogIHJlbmFtZShQb3JuaHViID0gIlBvcm5odWJJbmRleCglKSIpDQoNCmRhdGEudG9wLndvcmxkIDwtIG1lcmdlKHggPSBkYXRhLnRvcC53b3JsZCwgeSA9IGRmX3NhcnNfbGFzdGRhdGVfY29uZmlybWVkLCBieSA9ICJjb3VudHJ5IiwgYWxsLnggPSBUUlVFKSANCg0KDQpkYXRhLnRvcC53b3JsZCA8LSBtZXJnY291bnRyeShkYXRhLnRvcC53b3JsZCwgZGZfdGVtcCkNCmluZGV4IDwtIGlzLm5hKGRhdGEudG9wLndvcmxkKQ0KZGF0YS50b3Aud29ybGRbaW5kZXhdIDwtIDANCmRhdGEudG9wLndvcmxkDQojVmlldyhkYXRhLnRvcC53b3JsZCkNCg0KDQpub3JtYWxpemUgPSBmdW5jdGlvbihkYXRhKXsNCiAgI3JldHVybiAoKGRhdGEgLSBtaW4oZGF0YSxuYS5ybSA9IFRSVUUpKS8obWF4KGRhdGEsbmEucm0gPSBUUlVFKSAtIG1pbihkYXRhLG5hLnJtID0gVFJVRSkpKQ0KICB6IDwtIHNjYWxlKGRhdGEpOw0KICB0YW5oKHovMikNCn0NCg0Kbm9ybV9kYXRhID0gYXMuZGF0YS5mcmFtZShhcHBseShkYXRhLnRvcC53b3JsZFssMjoxM10sMixub3JtYWxpemUpKQ0KY29ycl9kYXRhIDwtIG5vcm1fZGF0YQ0Kbm9ybV9kYXRhJGNvdW50cnkgPC0gYygiQXJnZW50aW5hIiwiQmFuZ2xhZGVzaCIsIkJyYXppbCIsIkNoaWxlIiwiQ29sb21iaWEiLCJGcmFuY2UiLCJHZXJtYW55IiwiSW5kaWEiLCJJcmFuIiwiSXRhbHkiLCJNZXhpY28iLCJQYWtpc3RhbiIsIlBlcnUiLCJSdXNzaWEiLCJzYXVkaSBBcmFiaWEiLCJTb3V0aCBBZnJpY2EiLCJTcGFpbiIsIlR1cmtleSIsIlVuaXRlZCBLaW5nZG9tIiwiVVMiKQ0Kbm9ybV9kYXRhIDwtIG5vcm1fZGF0YVssYyhuY29sKG5vcm1fZGF0YSksMToobmNvbChub3JtX2RhdGEpLTEpKV0NCnJvd25hbWVzKG5vcm1fZGF0YSkgPC0gbm9ybV9kYXRhWywxXQ0Kbm9ybV9kYXRhWywxXSA8LSBOVUxMDQoNCiNoZWF0bWFwKGFzLm1hdHJpeChub3JtX2RhdGFbLCAtMV0pLHNjYWxlPSJjb2x1bW4iLGNvbD0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDgsICJCbHVlcyIpKSgyNSkpDQojbGVnZW5kKHg9ImJvdHRvbXJpZ2h0IiwgbGVnZW5kPWMoIi0xIiwgIjAiLCAiMSIpLCANCiMgICAgIGZpbGw9Y29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDgsICJCbHVlcyIpKSgzKSkNCg0KIyBpbnN0YWxsLnBhY2thZ2VzKCJncGxvdHMiKQ0KbGlicmFyeSgiZ3Bsb3RzIikNCmxpYnJhcnkoInN0cmluZ3IiKQ0Kbm9ybV9kYXRhX3Bsb3QgPC0gc2VsZWN0KG5vcm1fZGF0YSwiY29uZmlybS5yYXRlIiwiZGVhdGgucmF0ZSIsInJlY292ZXIucmF0ZSIsImhlYWx0aGNhcmUiLCJQb3JuaHViIiwiR0RQIiwiYXZnX3RlbXAiLCAic2FycyIpDQpub3JtX2RhdGFfcGxvdA0Kd29ybGRfY2x1c3QgPC0gYXMubWF0cml4KG5vcm1fZGF0YV9wbG90KQ0KaGVhdG1hcC5jbHVzdCA8LSBoZWF0bWFwLjIoYXMubWF0cml4KG5vcm1fZGF0YV9wbG90KSwNCiAgICAgICAgICAgICAgICAgICAgc2NhbGU9Im5vbmUiLCANCiAgICAgICAgICAgICAgICAgICAgY29sID0gY29sb3JSYW1wUGFsZXR0ZShjKCIjNkQ5RUMxIiwid2hpdGUiLCIjRTQ2NzI2IikpKG4gPSAyMDApLA0KICAgICAgICAgICAgICAgICAgICBtYXJnaW5zPWMoMTAsNiksdHJhY2U9ImNvbHVtbiIpDQojZ2x5LmhlYXRtYXAyIDwtIHBsb3RseV9idWlsZChoZWF0bWFwLmNsdXN0KQ0KDQoNCm5vcm1fZGF0YTIgPSBhcy5kYXRhLmZyYW1lKGFwcGx5KGRhdGEudG9wLndvcmxkWywyOjEzXSwyLG5vcm1hbGl6ZSkpDQpub3JtX2RhdGEyJGNvdW50cnkgPC0gYygiQXJnZW50aW5hIiwiQmFuZ2xhZGVzaCIsIkJyYXppbCIsIkNoaWxlIiwiQ29sb21iaWEiLCJGcmFuY2UiLCJHZXJtYW55IiwiSW5kaWEiLCJJcmFuIiwiSXRhbHkiLCJNZXhpY28iLCJQYWtpc3RhbiIsIlBlcnUiLCJSdXNzaWEiLCJzYXVkaSBBcmFiaWEiLCJTb3V0aCBBZnJpY2EiLCJTcGFpbiIsIlR1cmtleSIsIlVuaXRlZCBLaW5nZG9tIiwiVVMiKQ0KI1ZpZXcobm9ybV9kYXRhMikNCm5vcm1fZGF0YV9wbG90MiA8LSBzZWxlY3Qobm9ybV9kYXRhMiwiY291bnRyeSIsImNvbmZpcm0ucmF0ZSIsImRlYXRoLnJhdGUiLCJyZWNvdmVyLnJhdGUiLCJoZWFsdGhjYXJlIiwiUG9ybmh1YiIsIkdEUCIsImF2Z190ZW1wIiwgInNhcnMiKQ0KI1ZpZXcobm9ybV9kYXRhX3Bsb3QyKQ0Kbm9ybV9kYXRhX3Bsb3QyICU8PiUgZ2F0aGVyKGtleT10eXBlLCB2YWx1ZT1jb3VudCwgLWMoY291bnRyeSkpDQpsZXZlbF9vcmRlciA8LSBmYWN0b3Iobm9ybV9kYXRhX3Bsb3QyJHR5cGUsDQogICAgICAgICAgICAgICAgICAgICAgbGV2ZWwgPWMoInNhcnMiLCJQb3JuaHViIiwiR0RQIiwiYXZnX3RlbXAiLCJoZWFsdGhjYXJlIiwicmVjb3Zlci5yYXRlIiwiZGVhdGgucmF0ZSIsImNvbmZpcm0ucmF0ZSIpKQ0KI1ZpZXcobGV2ZWxfb3JkZXIpDQpnZ3Bsb3QoZGF0YSA9IG5vcm1fZGF0YV9wbG90MiwgYWVzKHg9Y291bnRyeSwgeT1sZXZlbF9vcmRlciwgZmlsbD1jb3VudCkpICsgDQogIGdlb21fdGlsZSgpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAicGluayIsIGhpZ2ggPSAiYmx1ZSIpICsNCiAgeGxhYigiIikgKw0KICB5bGFiKCIiKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLHZqdXN0ID0gMSkpKw0KICB0aGVtZSgNCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgI2xlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICApDQoNCmBgYA0KDQpgYGB7cn0NCiNjb3JyZWxhdGlvbg0KY29ycl9kYXRhICU8PiUgc2VsZWN0KGMoR0RQLGNvbmZpcm0ucmF0ZSxkZWF0aC5yYXRlLHJlY292ZXIucmF0ZSxoZWFsdGhjYXJlLGF2Z190ZW1wLFBvcm5odWIsIHNhcnMpKQ0KaGVhZChjb3JyX2RhdGEpDQpjb3IoY29ycl9kYXRhKQ0KcGxvdGNvcnIgPC0gZ2djb3JycGxvdChjb3IoY29ycl9kYXRhKSxoYy5vcmRlciA9IFRSVUUsDQogICAgICAgICAgIG91dGxpbmUuY29sb3IgPSAid2hpdGUiLA0KICAgICAgICAgICBjb2xvcnMgPSBjKCIjNkQ5RUMxIiwid2hpdGUiLCIjRTQ2NzI2IiksDQogICAgICAgICAgIGxhYiA9IFRSVUUpDQoNCnBsb3Rjb3JyDQpgYGANCg0KYGBge3J9DQojIyBEYXRhIGluIFVTDQoNCmRmX3VzIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGNvdmlkdXMiKSkNCmRmX3VzIDwtIGFzLmRhdGEuZnJhbWUoZGZfdXMpIA0KZGZfdXMgPC0gc2VsZWN0KGRmX3VzLCBkYXRlLCBzdGF0ZSwgY2FzZXMsIGRlYXRocykNCg0KZGZfdXNfcG9wIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGRhdGFfcG9wdWxhdGlvbiIpKSANCmRmX3VzX3BvcCA8LSBhcy5kYXRhLmZyYW1lKGRmX3VzX3BvcCkNCg0KZGZfdXNfZ2VuZGVyIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGRhdGFfZ2VuZGVyIikpIA0KZGZfdXNfZ2VuZGVyIDwtIGFzLmRhdGEuZnJhbWUoZGZfdXNfZ2VuZGVyKQ0KDQpkZl91c19ldGhuaWMgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gZGF0YV9ldGhuaWMiKSkgDQpkZl91c19ldGhuaWMgPC0gYXMuZGF0YS5mcmFtZShkZl91c19ldGhuaWMpDQoNCmRmX3VzX2xvY2tkb3duIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGRhdGFfbG9ja2Rvd24iKSkgDQpkZl91c19sb2NrZG93biA8LSBhcy5kYXRhLmZyYW1lKGRmX3VzX2xvY2tkb3duKQ0KDQpkZl91c19oZWFsdGggPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gZGF0YV9oZWFsdGgiKSkgDQpkZl91c19oZWFsdGggPC0gYXMuZGF0YS5mcmFtZShkZl91c19oZWFsdGgpDQoNCmRmX3VzX3Rlc3RpbmcgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gZGF0YV90ZXN0aW5nIikpIA0KZGZfdXNfdGVzdGluZyA8LSBhcy5kYXRhLmZyYW1lKGRmX3VzX3Rlc3RpbmcpDQoNCmBgYA0KDQpgYGB7cn0NCmRmX3VzIDwtIGRmX3VzICAlPiUNCiAgbXV0YXRlKGRhdGUgPSBkYXRlICU+JSBtZHkoKSkgJT4lDQogIHJlbmFtZSgiY29uZmlybWVkIiA9ICJjYXNlcyIpDQojZGF0YS51cw0KZGF0ZXMudXMgPC0gZGZfdXNbLDFdDQpyYW5nZShkYXRlcy51cykNCm1pbi5kYXRlLnVzIDwtIG1pbihkYXRlcy51cykNCm1heC5kYXRlLnVzIDwtIG1heChkYXRlcy51cykNCm1pbi5kYXRlLnR4dC51cyA8LSBtaW4uZGF0ZS51cyAlPiUgZm9ybWF0KCclZCAlYiAlWScpDQptYXguZGF0ZS50eHQudXMgPC0gbWF4LmRhdGUudXMgJT4lIGZvcm1hdCgnJWQgJWIgJVknKQ0KZGF5MS51cyA8LSBtaW4oZGZfdXMkZGF0ZSkNCg0KZGF0YS51cy50b3RhbCA8LSBkZl91cyAlPiUgZ3JvdXBfYnkoZGF0ZSkgJT4lDQogIHN1bW1hcmlzZShzdGF0ZT0nVVMnLA0KICAgICAgICAgICAgY29uZmlybWVkID0gc3VtKGNvbmZpcm1lZCwgbmEucm09VCksDQogICAgICAgICAgICBkZWF0aHMgPSBzdW0oZGVhdGhzLCBuYS5ybT1UKSkNCiNWaWV3KGRhdGEudXMudG90YWwpDQoNCmRhdGEudXMgPC0gZGZfdXMNCmRhdGEudXMgJTw+JSByYmluZChkYXRhLnVzLnRvdGFsKQ0KI1ZpZXcoZGF0YS51cykNCg0KZGF0YS51cy5sb25nIDwtIGRhdGEudXMgJT4lIA0KICBnYXRoZXIoa2V5ID0gdHlwZSwgdmFsdWUgPSBjb3VudCwgLWMoZGF0ZSwgc3RhdGUpKSANCiNWaWV3KGRhdGEudXMubG9uZykNCg0KdXMudG90YWwgPC0gZGF0YS51cy50b3RhbCAlPiUNCiAgbXV0YXRlKG5ldy5jb25maXJtZWQgPSBpZmVsc2UoZGF0ZSA9PSBkYXkxLCAwLCBjb25maXJtZWQgLSBsYWcoY29uZmlybWVkLCBuPTEpKSwNCiAgICAgICAgICAgICAgICBuZXcuZGVhdGhzID0gaWZlbHNlKGRhdGUgPT0gZGF5MSwgMCwgZGVhdGhzIC0gbGFnKGRlYXRocywgbj0xKSkpDQoNCnVzLnRvdGFsICU8PiUgbXV0YXRlKG5ldy5jb25maXJtZWQgPSBpZmVsc2UobmV3LmNvbmZpcm1lZCA8IDAsIDAsIG5ldy5jb25maXJtZWQpLA0KICAgICAgICAgICAgICAgICBuZXcuZGVhdGhzID0gaWZlbHNlKG5ldy5kZWF0aHMgPCAwLCAwLCBuZXcuZGVhdGhzKSkNCnVzLnRvdGFsDQoNCm1vc3RfdXMgPC0gdXMudG90YWwgJT4lIGZpbHRlcihkYXRlID09IG1heC5kYXRlLnVzKQ0KDQp1cy50b3RhbC5sb25nIDwtIHVzLnRvdGFsICU+JSANCiAgZ2F0aGVyKGtleSA9IHR5cGUsIHZhbHVlID0gY291bnQsIC1jKGRhdGUsIHN0YXRlKSkNCg0KI1ZpZXcodXMudG90YWwubG9uZykNCmBgYA0KDQoNCmBgYHtyfQ0KcGxvdF91cy5jYXNlcyA8LSBkYXRhLnVzLmxvbmcgJT4lIGZpbHRlcihzdGF0ZSA9PSAiVVMiKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IGNvdW50KSkgKw0KICBnZW9tX2FyZWEoYWVzKGZpbGw9dHlwZSksIGFscGhhPTAuNSkgKw0KIyAgbGFicyh0aXRsZSA9IHBhc3RlMCgiQ3VtdWxhdGl2ZSBjYXNlcyBpbiBVUyA6ICIsIG1pbi5kYXRlLnR4dC51cywgJy0nLCBtYXguZGF0ZS50eHQudXMsICIgKFN0YWNrLCBMb2cgU2NhbGUpIikpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSdsb2cxMCcpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoJ3JlZCcsICdibGFjaycpKSsNCiAgeWxhYigiIikgKw0KICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OCkpDQojVmlldyh1cy50b3RhbC5sb25nICkNCnBsb3RfdXMubmV3Y29uZiA8LSB1cy50b3RhbC5sb25nICU+JQ0KICBmaWx0ZXIodHlwZSAlaW4lIGMoIm5ldy5jb25maXJtZWQiLCJuZXcuZGVhdGhzIikpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gY291bnQsIGNvbG9yID0gdHlwZSkpICsgDQogIGdlb21fbGluZSgpICsgDQogICNsYWJzKHRpdGxlID0gcGFzdGUwKCJEYWlseSBjb25maXJtZWQgY2FzZXMgaW4gVVMgOiAiLCBtaW4uZGF0ZS50eHQudXMsICctJywgbWF4LmRhdGUudHh0LnVzKSkgKw0KICB4bGFiKCJEYXRlIikgKw0KICB5bGFiKCJDb25maXJtZWQgY2FzZXMiKQ0KDQpnbHkucGxvdF91cy5jYXNlcyA8LSBnZ3Bsb3RseShwbG90X3VzLmNhc2VzKQ0KZ2x5LnBsb3RfdXMuY2FzZXMgPC0gZ2x5LnBsb3RfdXMuY2FzZXMgJT4lIA0KICBsYXlvdXQodGl0bGUgPSBwYXN0ZTAoIjxiPkN1bXVsYXRpdmUgY2FzZXMgaW4gVVMgOiAiLCBtaW4uZGF0ZS50eHQudXMsICctJywgbWF4LmRhdGUudHh0LnVzLCAiIChTdGFjaywgTG9nIFNjYWxlKSIpLCANCiAgICAgICAgIGZvbnQ9bGlzdChzaXplID0gMTApKQ0KZ2x5LnBsb3RfdXMubmV3Y29uZiA8LSBnZ3Bsb3RseShwbG90X3VzLm5ld2NvbmYpICU+JSANCiAgbGF5b3V0KHRpdGxlID0gcGFzdGUwKCI8Yj5EYWlseSBjb25maXJtZWQgY2FzZXMgaW4gVVMgOiAiLCBtaW4uZGF0ZS50eHQudXMsICctJywgbWF4LmRhdGUudHh0LnVzKSwgDQogICAgICAgICBmb250PWxpc3Qoc2l6ZSA9IDEwKSkNCg0KZ2x5LnBsb3RfdXMuY2FzZXMgIA0KZ2x5LnBsb3RfdXMubmV3Y29uZg0KDQpgYGANCg0KYGBge3J9DQpkYXRhLnVzICU8PiUgbXV0YXRlKG5ldy5jb25maXJtZWQgPSBpZmVsc2UoZGF0ZSA9PSBkYXkxLCBOQSwgY29uZmlybWVkIC0gbGFnKGNvbmZpcm1lZCwgbj0xKSksDQogICAgICAgICAgICAgICAgIG5ldy5kZWF0aHMgPSBpZmVsc2UoZGF0ZSA9PSBkYXkxLCBOQSwgZGVhdGhzIC0gbGFnKGRlYXRocywgbj0xKSkpDQoNCmRhdGEudXMgJTw+JSBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShuZXcuY29uZmlybWVkIDwgMCwgMCwgbmV3LmNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgIG5ldy5kZWF0aHMgPSBpZmVsc2UobmV3LmRlYXRocyA8IDAsIDAsIG5ldy5kZWF0aHMpKQ0KI1ZpZXcoZGF0YS51cykNCg0KI2RhdGEudXMuZGFpbHkgPC0gZGF0YS51cyAlPiUgZmlsdGVyKHN0YXRlID09ICJVUyIpDQojVmlldyhkYXRhLnVzLmRhaWx5KQ0KDQpkYXRhLnVzLnBvcCA8LSBkZl91c19wb3AgJT4lIHNlbGVjdChTdGF0ZSwgUG9wdWxhdGlvbikgJT4lDQogIHJlbmFtZSgic3RhdGUiID0gIlN0YXRlIikgDQojZGF0YS51cy5wb3ANCg0KZGF0YS51cy5nZW5kZXIgPC0gZGZfdXNfZ2VuZGVyICU+JSBzZWxlY3QoU3RhdGUsIE1hbGUsIEZlbWFsZSkgJT4lDQogIHJlbmFtZSgic3RhdGUiID0gIlN0YXRlIikgDQpkYXRhLnVzLmdlbmRlcg0KDQpkYXRhLnVzLmxhdGVzdCA8LSBkYXRhLnVzICU+JQ0KICBmaWx0ZXIoZGF0ZSA9PSBtYXguZGF0ZS51cykgJT4lIA0KICBtZXJnZShkYXRhLnVzLnBvcCwgYnkgPSAic3RhdGUiLCBhbGwueCA9IFQpICU+JQ0KICBtZXJnZShkYXRhLnVzLmdlbmRlciwgYnkgPSAic3RhdGUiLCBhbGwueCA9IFQpDQojVmlldyhkYXRhLnVzLmxhdGVzdCkNCg0KZGF0YS51cy5sYXRlc3QkUG9wdWxhdGlvbltkYXRhLnVzLmxhdGVzdCRzdGF0ZSA9PSAiVVMiXSA8LSBzdW0oZGF0YS51cy5wb3AkUG9wdWxhdGlvbikNCmRhdGEudXMubGF0ZXN0ICU8PiUgbXV0YXRlKHJhbmtpbmcgPSBkZW5zZV9yYW5rKGRlc2MoY29uZmlybWVkKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBjb25maXJtZWQucmF0ZSA9ICgxMDAgKiBjb25maXJtZWQgLyBQb3B1bGF0aW9uKSAlPiUgcm91bmQoMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBkZWF0aC5yYXRlID0gKDEwMCAqIGRlYXRocyAvIGNvbmZpcm1lZCkgJT4lIHJvdW5kKDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgTWFsZS5jb25maXJtZWQgPSAoTWFsZSAqIGNvbmZpcm1lZCkgJT4lIHJvdW5kKDApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgRmVtYWxlLmNvbmZpcm1lZCA9IEZlbWFsZSAqIGNvbmZpcm1lZCAlPiUgcm91bmQoMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBNYWxlLmRlYXRocyA9IE1hbGUgKiBkZWF0aHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBGZW1hbGUuZGVhdGhzID0gRmVtYWxlICogZGVhdGhzKSAlPiUNCiAgYXJyYW5nZShyYW5raW5nKSANCg0KdG9wLnVzIDwtIGRhdGEudXMubGF0ZXN0WywxXQ0KdG9wLnVzDQoNCiNWaWV3KHRvcC51cykNCg0KZGF0YS51cy5sYXRlc3Quc2hvdyA8LSBkYXRhLnVzLmxhdGVzdCAlPiUgc2VsZWN0KHN0YXRlLGRhdGUsY29uZmlybWVkLGRlYXRocywgY29uZmlybWVkLnJhdGUsIGRlYXRoLnJhdGUpDQojVmlldyhkYXRhLnVzLmxhdGVzdC5zaG93KQ0KYGBgDQoNCmBgYHtyfQ0KIyBMaXN0IG9mIHRvcCAyMCBzdGF0ZQ0KayA8LSAyMA0KZGF0YS51cy50b3AgPC0gZGF0YS51cy5sYXRlc3QgJT4lDQogIGZpbHRlcihyYW5raW5nIDw9IGsrMSkgJT4lIA0KICBhcnJhbmdlKHJhbmtpbmcpIA0KI1ZpZXcoZGF0YS51cy50b3ApDQoNCnVzLnN0YXRlLnRvcCA8LSBkYXRhLnVzLnRvcCAlPiUgcHVsbChzdGF0ZSkgJT4lIGFzLmNoYXJhY3RlcigpDQp1cy5zdGF0ZS50b3AgICU+JSBzZXRkaWZmKCdVUycpICU+JSBwcmludCgpDQoNCiMgY29uZmlybWVkIHJhdGUgJiBkZWF0aCByYXRlIG9mIHRvcCAyMCBzdGF0ZQ0KZy5yYXRlIDwtIGRhdGEudXMubGF0ZXN0ICU+JSBmaWx0ZXIoc3RhdGUgJWluJSB1cy5zdGF0ZS50b3AgJiBzdGF0ZSAhPSAiVVMiKSAlPiUNCiAgc2VsZWN0KHN0YXRlLCBjb25maXJtZWQucmF0ZSwgZGVhdGgucmF0ZSwgcmFua2luZykgJT4lDQogIGdhdGhlcihrZXkgPSBUeXBlLCB2YWx1ZSA9IFBlcmNlbnQsIC1jKHN0YXRlLCByYW5raW5nKSkgJT4lDQogIGdncGxvdChhZXMoeD1yZW9yZGVyKHN0YXRlLCAtZGVzYyhyYW5raW5nKSksIHk9UGVyY2VudCwgZmlsbCA9IFBlcmNlbnQpKSArDQogIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICIjZWJiYzYyIiwgaGlnaCA9ICIjYjQyMDA2IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPVBlcmNlbnQsIHk9UGVyY2VudCksIHNpemU9Mywgdmp1c3Q9MCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJycpICsNCiAgbGFicyh0aXRsZT1wYXN0ZTAoJ0NvbmZpcm1lZCBSYXRlICYgRGVhdGggUmF0ZSBvZiBUb3AgMjAgU3RhdGUgaW4gVVMnKSkgKw0KICAjc2NhbGVfZmlsbF9jb250aW51b3VzKG5hbWU9J1N0YXRlJywgbGFiZWxzPWFlcyhQZXJjZW50KSkgKw0KICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb249J25vbmUnLA0KICAgICAgICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEzKSwNCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpLA0KICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKSArDQogIGZhY2V0X3dyYXAoflR5cGUsIG5jb2w9MSwgc2NhbGVzPSdmcmVlX3knKSANCg0KZy5yYXRlDQpgYGANCg0KYGBge3J9DQp1cy5jb25maXJtZWQubnVtIDwtIGRhdGEudXMudG9wJGNvbmZpcm1lZFtkYXRhLnVzLnRvcCRzdGF0ZSA9PSAiVVMiXSAlPiUgYXMubnVtZXJpYygpDQp1cy5jb25maXJtZWQubnVtDQoNCmRhdGEudXMudG9wICU8PiUgbXV0YXRlKGNvbmZpcm1lZC5wZXIudXMgPSAoY29uZmlybWVkICogMTAwIC8gdXMuY29uZmlybWVkLm51bSkgJT4lIHJvdW5kKDEpKQ0KZGF0YS51cy50b3ANCg0KZy51cy50b3AxIDwtIGRhdGEudXMudG9wICU+JQ0KICBmaWx0ZXIoc3RhdGUgIT0gIlVTIikgJT4lDQogIHNlbGVjdChzdGF0ZSwgY29uZmlybWVkLCBjb25maXJtZWQucGVyLnVzLCByYW5raW5nKSAlPiUNCiAgZ2F0aGVyKGtleSA9IFR5cGUsIHZhbHVlID0gY291bnQsIC1jKHN0YXRlLCByYW5raW5nLCBjb25maXJtZWQucGVyLnVzKSkgJT4lDQogIGFycmFuZ2UocmFua2luZykgJT4lDQogIA0KICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKHN0YXRlLCByYW5raW5nKSwgeSA9IGNvdW50LCBmaWxsID0gY291bnQpKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICAjbGFicyh0aXRsZSA9ICIyMCBzdGF0ZSBpbiBVUyB3aXRoIG1vc3QgY29uZmlybWVkIGNhc2VzIikgKw0KICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAiIzkzREJGRiIsIGhpZ2ggPSAiI0ZGNzc3MSIpICsNCiAgeGxhYigiIikgKyANCiAgeWxhYigiQ29uZmlybWVkIENhc2VzIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlMChjb25maXJtZWQucGVyLnVzLCAiJSIpKSwgc2l6ZT0zLCB2anVzdD0tMC41KSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsdmp1c3QgPSAwLjUpKSsNCiAgdGhlbWUoDQogICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICNsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKQ0KDQpnLnVzLnRvcDENCg0KZ2x5LnVzLnRvcDEgPC0gZ2dwbG90bHkoZy51cy50b3AxKQ0KZ2x5LnVzLnRvcDENCmBgYA0KDQpgYGB7cn0NCmRhdGEudXMubGF0ZXN0LmNvcnIgPC0gZGZfdXMgJT4lZmlsdGVyKGRhdGU9PW1heC5kYXRlLnVzKQ0KI1ZpZXcoZGF0YS51cy5sYXRlc3QuY29ycikNCg0KZGF0YS51cy5sYXRlc3QuY29yciAlPD4lIG11dGF0ZShyYW5raW5nID0gZGVuc2VfcmFuayhkZXNjKGNvbmZpcm1lZCkpKSAlPiUgYXJyYW5nZShyYW5raW5nKQ0KdG9wLnVzIDwtIGRhdGEudXMubGF0ZXN0LmNvcnJbLDJdDQojdG9wLnVzDQoNCiMgTGlzdCBvZiB0b3AgMjAgc3RhdGUNCmsgPC0gMTkNCmRhdGEudXMubGF0ZXN0LnRvcCA8LSBkYXRhLnVzLmxhdGVzdC5jb3JyICU+JQ0KICAgIGZpbHRlcihyYW5raW5nIDw9IGsrMSkgJT4lIA0KICAgIGFycmFuZ2UocmFua2luZykgDQojVmlldyhkYXRhLnVzLmxhdGVzdC50b3ApDQp1cy5zdGF0ZS50b3AgPC0gZGF0YS51cy5sYXRlc3QudG9wICU+JSBwdWxsKHN0YXRlKSAlPiUgYXMuY2hhcmFjdGVyKCkNCnVzLnN0YXRlLnRvcCAgJT4lIHNldGRpZmYoJ1VTJykgJT4lIHByaW50KCkNCiNWaWV3KHVzLnN0YXRlLnRvcCkNCmBgYA0KDQoNCg0KYGBge3J9DQojZ2VuZGVyIGluIHVzDQpkZl91c19nZW5kZXIgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gZGF0YV9nZW5kZXIiKSkNCmRmX3VzX2dlbmRlciA8LSBhcy5kYXRhLmZyYW1lKGRmX3VzX2dlbmRlcikNCmRmX3VzX2dlbmRlciA8LSBzZWxlY3QoZGZfdXNfZ2VuZGVyLGMoIlN0YXRlIiwiTWFsZSIsIkZlbWFsZSIpKQ0KZGZfdXNfZ2VuZGVyIDwtIHJlbmFtZShkZl91c19nZW5kZXIsInN0YXRlIj0iU3RhdGUiKQ0KZGZfdXNfZ2VuZGVyDQoNCiNwb3B1bGF0aW9uIGluIHVzDQpkZl91c19wb3AgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gZGF0YV9wb3B1bGF0aW9uIikpDQpkZl91c19wb3AgPC0gYXMuZGF0YS5mcmFtZShkZl91c19wb3ApDQpkZl91c19wb3AgPC0gc2VsZWN0KGRmX3VzX3BvcCxjKCJTdGF0ZSIsIlBvcHVsYXRpb24iKSkNCmRmX3VzX3BvcCA8LSByZW5hbWUoZGZfdXNfcG9wLCJzdGF0ZSI9IlN0YXRlIikNCmRmX3VzX3BvcA0KDQojbG9ja2Rvd24gaW4gdXMNCmRmX3VzX2xvY2tkb3duIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGRhdGFfbG9ja2Rvd24iKSkNCmRmX3VzX2xvY2tkb3duIDwtIGFzLmRhdGEuZnJhbWUoZGZfdXNfbG9ja2Rvd24pDQpkZl91c19sb2NrZG93biA8LSBzZWxlY3QoZGZfdXNfbG9ja2Rvd24sYygiU3RhdGUiLCJEYXkgbG9ja2Rvd24iKSkNCmRmX3VzX2xvY2tkb3duIDwtIHJlbmFtZShkZl91c19sb2NrZG93biwic3RhdGUiPSJTdGF0ZSIpDQpkZl91c19sb2NrZG93bg0KDQojR0RQIGluIHVzDQpkZl91c19nZHAgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gdXNfZ2RwIikpDQpkZl91c19nZHAgIDwtIGFzLmRhdGEuZnJhbWUoZGZfdXNfZ2RwICkNCmRmX3VzX2dkcCAgPC0gc2VsZWN0KGRmX3VzX2dkcCAsYygiU3RhdGUiLCJHRFBzIikpDQpkZl91c19nZHAgIDwtIHJlbmFtZShkZl91c19nZHAgLCJzdGF0ZSI9IlN0YXRlIikNCmRmX3VzX2dkcCANCg0KI2hvbWVsZXNzIGluIHVzDQpkZl91c19ob21lbGVzcyA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSB1c19ob21lbGVzcyIpKQ0KZGZfdXNfaG9tZWxlc3MgPC0gYXMuZGF0YS5mcmFtZShkZl91c19ob21lbGVzcykNCmRmX3VzX2hvbWVsZXNzIDwtIHNlbGVjdChkZl91c19ob21lbGVzcyxjKCJTdGF0ZSIsIkhvbWVsZXNzIikpDQpkZl91c19ob21lbGVzcyA8LSByZW5hbWUoZGZfdXNfaG9tZWxlc3MsInN0YXRlIj0iU3RhdGUiKQ0KZGZfdXNfaG9tZWxlc3MNCg0KI1ZpZXcoZGZfdXMpDQoNCg0KYGBgDQpgYGB7cn0NCiNtZXJnZQ0KbWVyZ2NvdW50cnkgPSBmdW5jdGlvbihkYXRhMSxkYXRhMil7DQogIGRhdGEgPC0gbWVyZ2UoeCA9IGRhdGExLCB5ID0gZGF0YTIsIGJ5ID0gInN0YXRlIiwgYWxsLnggPSBUUlVFKSANCiAgcmV0dXJuKGRhdGEpDQp9DQoNCmRhdGEudG9wLnN0YXRlIDwtIGRhdGEudXMubGF0ZXN0LnRvcCAlPiUgZmlsdGVyKHN0YXRlICE9ICJVUyIpICU+JQ0KICBzZWxlY3Qoc3RhdGUsIGNvbmZpcm1lZCwgZGVhdGhzKQ0KI1ZpZXcoZGF0YS50b3Auc3RhdGUpDQoNCmRmX0FsbHVzIDwtIG1lcmdjb3VudHJ5KGRhdGEudG9wLnN0YXRlLCBkZl91c19nZW5kZXIpDQoNCmRmX0FsbHVzIDwtIG1lcmdjb3VudHJ5KGRmX0FsbHVzLCBkZl91c19wb3ApIA0KDQpkZl9BbGx1cyA8LSBtZXJnY291bnRyeShkZl9BbGx1cywgZGZfdXNfbG9ja2Rvd24pIA0KDQpkZl9BbGx1cyA8LSBtZXJnY291bnRyeShkZl9BbGx1cywgZGZfdXNfZ2RwKQ0KDQpkZl9BbGx1cyA8LSBtZXJnY291bnRyeShkZl9BbGx1cywgZGZfdXNfaG9tZWxlc3MpDQoNCiNWaWV3KGRmX0FsbHVzKQ0KYGBgDQoNCmBgYHtyfQ0KaW5kZXggPC0gaXMubmEoZGZfQWxsdXMpDQpkZl9BbGx1c1tpbmRleF0gPC0gMA0KI1ZpZXcoZGZfQWxsdXMpDQoNCm5vcm1hbGl6ZSA9IGZ1bmN0aW9uKGRhdGEpew0KICAjcmV0dXJuICgoZGF0YSAtIG1pbihkYXRhLG5hLnJtID0gVFJVRSkpLyhtYXgoZGF0YSxuYS5ybSA9IFRSVUUpIC0gbWluKGRhdGEsbmEucm0gPSBUUlVFKSkpDQogIHogPC0gc2NhbGUoZGF0YSk7DQogIHRhbmgoei8yKQ0KfQ0KQWxsdXMgPSBhcy5kYXRhLmZyYW1lKGFwcGx5KGRmX0FsbHVzWywyOjldLDIsbm9ybWFsaXplKSkNCmNvcnJfZGF0YVVTIDwtIEFsbHVzIA0KDQojVmlldyhjb3JyX2RhdGFVUykNCmBgYA0KDQpgYGB7cn0NCkFsbHVzJHN0YXRlIDwtIGMoZGZfQWxsdXMkc3RhdGUpDQojVmlldyhBbGx1cykNCg0KY29ycl9kYXRhVVMgPC0gcmVuYW1lKGNvcnJfZGF0YVVTICwiRGF5bG9ja2Rvd24iID0gIkRheSBsb2NrZG93biIpDQpgYGANCg0KYGBge3J9DQpBbGx1c19wbG90IDwtIHNlbGVjdChBbGx1cywic3RhdGUiLCJjb25maXJtZWQiLCJkZWF0aHMiLCJNYWxlIiwiRmVtYWxlIiwiUG9wdWxhdGlvbiIsIkRheSBsb2NrZG93biIsIkdEUHMiLCJIb21lbGVzcyIpDQpBbGx1c19wbG90ICU8PiUgZ2F0aGVyKGtleT10eXBlLCB2YWx1ZT1jb3VudCwgLWMoc3RhdGUpKQ0KbGV2ZWxfb3JkZXIgPC0gZmFjdG9yKEFsbHVzX3Bsb3QkdHlwZSwgDQogICAgICAgICAgICAgICAgICAgICAgbGV2ZWwgPSBjKCJjb25maXJtZWQiLCJkZWF0aHMiLCJNYWxlIiwiRmVtYWxlIiwiUG9wdWxhdGlvbiIsIkRheSBsb2NrZG93biIsIkdEUHMiLCJIb21lbGVzcyIpKQ0KDQpBbGx1c19IZWF0IDwtIEFsbHVzWyxjKG5jb2woQWxsdXMpLDE6KG5jb2woQWxsdXMpLTEpKV0NCnJvd25hbWVzKEFsbHVzX0hlYXQpIDwtIEFsbHVzX0hlYXRbLDFdDQpBbGx1c19IZWF0WywxXSA8LSBOVUxMDQpoZWF0bWFwLjIoYXMubWF0cml4KEFsbHVzX0hlYXQpLA0KICAgICAgICAgICAgICAgICAgICBzY2FsZT0ibm9uZSIsIA0KICAgICAgICAgICAgICAgICAgICBjb2wgPSBjb2xvclJhbXBQYWxldHRlKGMoIiM2RDlFQzEiLCJ3aGl0ZSIsIiNFNDY3MjYiKSkobiA9IDIwMCksDQogICAgICAgICAgICAgICAgICAgIG1hcmdpbnM9YygxMCw2KSx0cmFjZT0iY29sdW1uIikNCg0KaGVhdG1hcHVzIDwtIGdncGxvdChkYXRhID0gQWxsdXNfcGxvdCwgYWVzKHg9c3RhdGUsIHk9bGV2ZWxfb3JkZXIsIGZpbGw9Y291bnQpKSArIA0KICBnZW9tX3RpbGUoKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gInBpbmsiLCBoaWdoID0gImJsdWUiKSArDQogIHhsYWIoIiIpICsNCiAgeWxhYigiIikgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCx2anVzdCA9IDEpKSsNCiAgdGhlbWUoDQogICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICNsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKSArbGFicyh0aXRsZT0nVGhlIGhlYXRtYXAgb2YgQ09WSUQtMTkgaW5mZWN0aW9ucyBpbiBVUycpDQoNCmhlYXRtYXB1cw0KYGBgDQoNCg0KYGBge3J9DQojY29ycmVsYXRpb24NCmNvcnJfZGF0YVVTICU8PiUgc2VsZWN0KGMoY29uZmlybWVkLGRlYXRocyxNYWxlLEZlbWFsZSxQb3B1bGF0aW9uLERheWxvY2tkb3duLEdEUHMsSG9tZWxlc3MpKQ0KaGVhZChjb3JyX2RhdGFVUykNCmNvcihjb3JyX2RhdGFVUykNCmdnY29ycnBsb3QoY29yKGNvcnJfZGF0YVVTKSxoYy5vcmRlciA9IFRSVUUsDQogICAgICAgICAgIG91dGxpbmUuY29sb3IgPSAid2hpdGUiLA0KICAgICAgICAgICBjb2xvcnMgPSBjKCIjNkQ5RUMxIiwid2hpdGUiLCIjRTQ2NzI2IiksDQogICAgICAgICAgIGxhYiA9IFRSVUUpDQoNCg0KDQpgYGANCg0KYGBge3J9DQojQ292aWRfVGhhaWxhbmQNCmRmX3RoYWkgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gY292aWQxOV90aGFpbGFuZCIpKQ0KZGZfdGhhaSA8LSBhcy5kYXRhLmZyYW1lKGRmX3RoYWkpDQojVmlldyhkZl90aGFpKQ0KYGBgDQoNCmBgYHtyfQ0KI2NsZWFuIENvdmlkX1RoYWlsYW5kDQpkYXRlcy50aCA8LSBkZl90aGFpWywyXSU+JSBtZHkoKQ0KcmFuZ2UoZGF0ZXMudGgpDQptaW4uZGF0ZS50aCA8LSBtaW4oZGF0ZXMudGgpDQptYXguZGF0ZS50aCA8LSBtYXgoZGF0ZXMudGgpDQptaW4uZGF0ZS50eHQudGggPC0gbWluLmRhdGUudGggJT4lIGZvcm1hdCgnJWQgJWIgJVknKQ0KbWF4LmRhdGUudHh0LnRoIDwtIG1heC5kYXRlLnRoICU+JSBmb3JtYXQoJyVkICViICVZJykNCmBgYA0KDQpgYGB7cn0NCmRmX3RoYWkkYW5ub3VuY2VfZGF0ZSA8LSBtZHkoZGZfdGhhaSRhbm5vdW5jZV9kYXRlKQ0KZGZfdGhhaSRub3RpZmljYXRpb25fZGF0ZSA8LSBtZHkoZGZfdGhhaSRub3RpZmljYXRpb25fZGF0ZSkNCmRmX3RoYWkNCmBgYA0KDQpgYGB7cn0NCmRmX3RoYWkgPC0gZGZfdGhhaSAlPiUgc2VsZWN0KCFOby4pICU+JSBzZWxlY3QoIW5vdGlmaWNhdGlvbl9kYXRlKSAlPiUgDQogIGdyb3VwX2J5KGFubm91bmNlX2RhdGUpDQpkZl90aGFpDQojVmlldyhkZl90aGFpKQ0KYGBgDQoNCmBgYHtyfQ0KIyBUb3RhbCBjb25maXJtZWQgY2FzZXMgaW4gVGhhaWxhbmQNCmRhdGEudGhhaS5jb3VudCA8LSBkZl90aGFpICU+JQ0KICBzZWxlY3QoYW5ub3VuY2VfZGF0ZSkgJT4lDQogIHN1bW1hcmlzZShjb25maXJtZWQgPSBuKCkpICU+JSBhcy5kYXRhLmZyYW1lKCkNCiNWaWV3KGRhdGEudGhhaS5jb3VudCkNCmRhdGEudGhhaS5jb3VudCRjdW11bGF0aXZlX2NvbmZpcm1lZCA8LSBjdW1zdW0oZGF0YS50aGFpLmNvdW50WywgMl0pDQpgYGANCmBgYHtyfQ0KZGF0YS50aGFpLmNvdW50IDwtIGRhdGEudGhhaS5jb3VudCAlPiUgcmVuYW1lKG5ldy5jb25maXJtZWQ9Y29uZmlybWVkKSAlPiUgcmVuYW1lKGNvbmZpcm1lZD1jdW11bGF0aXZlX2NvbmZpcm1lZCkNCnRoYWkudG90YWwubG9uZyA8LSBkYXRhLnRoYWkuY291bnQgJT4lIA0KICBnYXRoZXIoa2V5ID0gdHlwZSwgdmFsdWUgPSBjb3VudCwgLWMoYW5ub3VuY2VfZGF0ZSkpDQp0aGFpLnRvdGFsLmxvbmcNCmBgYA0KDQpgYGB7cn0NCg0KcGxvdF90aGFpbGFuZC5jb25mIDwtIHRoYWkudG90YWwubG9uZyAlPiUNCiAgZmlsdGVyKHR5cGUgJWluJSBjKCJuZXcuY29uZmlybWVkIikpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBhbm5vdW5jZV9kYXRlLCB5ID0gY291bnQsIGNvbG9yID0gdHlwZSkpICsgDQogIGdlb21fbGluZSgpICsgDQogIHhsYWIoIkRhdGUiKSArDQogIHlsYWIoImNhc2VzIikNCg0KZ2x5LnBsb3RfdGhhaS5jYXNlcyA8LSBnZ3Bsb3RseShwbG90X3RoYWlsYW5kLmNvbmYpDQpnbHkucGxvdF90aGFpLmNhc2VzIDwtIGdseS5wbG90X3RoYWkuY2FzZXMgJT4lIA0KICBsYXlvdXQodGl0bGUgPSBwYXN0ZTAoIjxiPkRhaWx5IFRoYWkgQ29uZmlybWVkIENhc2VzIGluIFRoYWlsYW5kIDogSmFuIDIwMjAgLSBKYW4gMjAyMSIpLCANCiAgICAgICAgIGZvbnQ9bGlzdChzaXplID0gMTApKQ0KDQpnbHkucGxvdF90aGFpLmNhc2VzDQpgYGANCmBgYHtyfQ0KcGxvdF90aGFpbGFuZC5jdW11bGF0aXZlIDwtIHRoYWkudG90YWwubG9uZyAlPiUgDQogIGZpbHRlcih0eXBlICVpbiUgYygiY29uZmlybWVkIikpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBhbm5vdW5jZV9kYXRlLCB5ID0gY291bnQpKSArDQogIGdlb21fYXJlYShhZXMoZmlsbD10eXBlKSwgYWxwaGE9MC41KSArDQoNCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSdsb2cxMCcpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoJ3JlZCcpKSsNCiAgeWxhYigiIikgKw0KICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OCkpDQoNCmdseS5wbG90X3RoYWkuY3VtdWxhdGl2ZSA8LSBnZ3Bsb3RseShwbG90X3RoYWlsYW5kLmN1bXVsYXRpdmUpDQpnbHkucGxvdF90aGFpLmN1bXVsYXRpdmUgPC0gZ2x5LnBsb3RfdGhhaS5jdW11bGF0aXZlICU+JSANCiAgbGF5b3V0KHRpdGxlID0gcGFzdGUwKCI8Yj5DdW11bGF0aXZlIENhc2VzIGluIFRoYWlsYW5kIDogSmFuIDIwMjAgLSBKYW4gMjAyMSAoU3RhY2ssTG9nIHNjYWxlKSIpLCANCiAgICAgICAgIGZvbnQ9bGlzdChzaXplID0gMTApKQ0KDQpnbHkucGxvdF90aGFpLmN1bXVsYXRpdmUNCmBgYA0KDQoNCg0KYGBge3J9DQojIyBUaGFpIENvbmZpcm1lZCBDYXNlcyAoSmFuIDIwMjAgLSBKYW4gMjAyMQ0KcGxvdDEgPC0gZ2dwbG90KGRhdGEudGhhaS5jb3VudCwgYWVzKHg9YW5ub3VuY2VfZGF0ZSwgeT1jb25maXJtZWQpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCIgIikgKyB5bGFiKCJDb3VudCIpICsgbGFicyh0aXRsZT0nVGhhaSBDdW11bGF0aXZlIENvbmZpcm1lZCBDYXNlcyAoSmFuIDIwMjAgLSBKYW4gMjAyMSknKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQpwbG90MiA8LSBnZ3Bsb3QoZGF0YS50aGFpLmNvdW50LCBhZXMoeD1hbm5vdW5jZV9kYXRlLCB5PW5ldy5jb25maXJtZWQpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICAgIHhsYWIoIiAiKSArIHlsYWIoIkNvdW50IikrIGxhYnModGl0bGU9J1RoYWkgQ29uZmlybWVkIENhc2VzIChKYW4gMjAyMCAtIEphbiAyMDIxIGxvZyBzY2FsZSknKSArDQogICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKStzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9J2xvZzEwJykNCiMjIHNob3cgdHdvIHBsb3RzIHNpZGUgYnkgc2lkZQ0KZ3JpZC5hcnJhbmdlKHBsb3QxLCBwbG90MiwgbmNvbD0xKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCiMgQ29uZmlybWVkIGNhc2VzIGRpdmlkZWQgYnkgc2V4IChnZW5kZXIpDQpkZl90aGFpJHNleFtkZl90aGFpJHNleCA9PSAiIl0gPC0gIlVua25vd24iDQpkYXRhLnRoYWkuZ2VuZGVyIDwtIGRmX3RoYWkgJT4lDQogIGdyb3VwX2J5KHNleCkgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIG11dGF0ZShwZXJjZW50ID0gKGNvdW50IC8gc3VtKGNvdW50KSAqIDEwMCkgJT4lIHJvdW5kKDIpKSAlPiUNCiAgZmlsdGVyKHBlcmNlbnQ+MSklPiUNCiAgI211dGF0ZShwb3MgPSBjdW1zdW0ocGVyY2VudCkgLSAwLjUqcGVyY2VudCkgJT4lDQogIGFycmFuZ2UoZGVzYyhwZXJjZW50KSkNCg0KZGF0YS50aGFpLmdlbmRlcg0KYGBgDQoNCmBgYHtyfQ0KZGF0YS50aGFpLmdlbmRlciRzZXggPC0gZmFjdG9yKGRhdGEudGhhaS5nZW5kZXIkc2V4LCBsZXZlbHMgPSBhcy5jaGFyYWN0ZXIoZGF0YS50aGFpLmdlbmRlciRzZXgpKQ0KZGF0YS50aGFpLmdlbmRlciRzZXgNCmcudGguZ2VuZGVyIDwtIGRhdGEudGhhaS5nZW5kZXIgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSAiIiwgeSA9IHBlcmNlbnQsIGZpbGwgPSBzZXgpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEpICsNCiAgY29vcmRfcG9sYXIoInkiKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIGxhYnModGl0bGU9J0dlbmRlciBvZiBUaGFpIENvbmZpcm1lZCBDYXNlcyAoSmFuIDIwMjAgLSBKYW4gMjAyMSknKSsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChwZXJjZW50LCAiJSIpKSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gNSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpICsNCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpKSANCmcudGguZ2VuZGVyDQpgYGANCg0KYGBge3J9DQojIENvbmZpcm1lZCBjYXNlcyBkaXZpZGVkIGJ5IHByb3ZpbmNlX29mX29uc2V0DQpkYXRhLnRoYWkub25zZXQgPC0gZGZfdGhhaSAlPiUNCiAgICBncm91cF9ieShwcm92aW5jZV9vZl9vbnNldCkgJT4lDQogICAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiAgICBhcnJhbmdlKGRlc2MoY291bnQpKSU+JQ0KICAgIHJlbmFtZShvbnNldD0iY291bnQiKSU+JQ0KICAgIHJlbmFtZShwcm92aW5jZT0icHJvdmluY2Vfb2Zfb25zZXQiKQ0KZGF0YS50aGFpLm9uc2V0JHByb3ZpbmNlW2RhdGEudGhhaS5vbnNldCRwcm92aW5jZSA9PSAiIl0gPC0gIlVua25vd24iDQpkYXRhLnRoYWkub25zZXQNCmBgYA0KDQpgYGB7cn0NCiMgQ29uZmlybWVkIGNhc2VzIGRpdmlkZWQgYnkgcHJvdmluY2Vfb2ZfaXNvbGF0aW9uIA0KZGF0YS50aGFpLmlzb2xhdGlvbiA8LSBkZl90aGFpICU+JQ0KICAgIGdyb3VwX2J5KHByb3ZpbmNlX29mX2lzb2xhdGlvbikgJT4lDQogICAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiAgICBhcnJhbmdlKGRlc2MoY291bnQpKSU+JQ0KICAgIHJlbmFtZShpc29sYXRpb24gPSJjb3VudCIpJT4lDQogICAgcmVuYW1lKHByb3ZpbmNlPSJwcm92aW5jZV9vZl9pc29sYXRpb24iKQ0KDQpkYXRhLnRoYWkuaXNvbGF0aW9uJHByb3ZpbmNlW2RhdGEudGhhaS5pc29sYXRpb24kcHJvdmluY2UgPT0gIiJdIDwtICJVbmtub3duIg0KZGF0YS50aGFpLmlzb2xhdGlvbg0KYGBgDQoNCmBgYHtyfQ0KZGF0YS5wcm92aW5jZSA8LSBtZXJnZSh4ID0gZGF0YS50aGFpLm9uc2V0LCB5ID0gZGF0YS50aGFpLmlzb2xhdGlvbiwgYnkgPSAicHJvdmluY2UiLCBhbGwueCA9IFRSVUUpIA0KZGF0YS5wcm92aW5jZSA8LSBkYXRhLnByb3ZpbmNlJT4lZmlsdGVyKG9uc2V0PjEyNSkNCmRhdGEucHJvdmluY2UNCmBgYA0KDQpgYGB7cn0NCmRhdGEucHJvdmluY2UubG9uZyA8LSBkYXRhLnByb3ZpbmNlICU+JQ0KICAgIGdhdGhlcihrZXk9dHlwZSwgdmFsdWU9Y291bnQsIC1jKHByb3ZpbmNlKSkNCmRhdGEucHJvdmluY2UubG9uZw0KYGBgDQoNCmBgYHtyfQ0KcHJvdmluY2UudGhhaSA8LSBnZ3Bsb3QoZGF0YS5wcm92aW5jZS5sb25nLGFlcyh4PXByb3ZpbmNlLHk9Y291bnQpKSsNCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iixwb3NpdGlvbiA9ICJkb2RnZSIsYWVzKGZpbGw9dHlwZSkpKw0KICAgIGxhYnModGl0bGUgPSAiUHJvdmluY2Ugb2Ygb25zZXQgYW5kIFByb3ZpbmNlIG9mIGlzb2xhdGlvbiBpbiBUaGFpbGFuZCIpKw0KICAgIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgICAjbGVnZW5kLnBvc2l0aW9uPSdub25lJywNCiAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTIpLA0KICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEwKSwNCiAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpKyB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykNCmdseS5wcm92aW5jZS50aGFpIDwtIGdncGxvdGx5KHByb3ZpbmNlLnRoYWkpDQpnbHkucHJvdmluY2UudGhhaQ0KYGBgDQoNCmBgYHtyfQ0KIyBDb25maXJtZWQgY2FzZXMgZGl2aWRlZCBieSByaXNrDQpkYXRhLnRoYWkucmlzayA8LSBkZl90aGFpICU+JQ0KICBncm91cF9ieShyaXNrKSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiAgYXJyYW5nZShkZXNjKGNvdW50KSkNCmRhdGEudGhhaS5yaXNrDQpgYGANCg0KYGBge3J9DQojIENvbmZpcm1lZCBjYXNlcyBkaXZpZGVkIGJ5IHJpc2sNCmRhdGEudGhhaS5yaXNrIDwtIGRmX3RoYWkgJT4lDQogIGdyb3VwX2J5KHJpc2spICU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICBtdXRhdGUocGVyY2VudCA9IChjb3VudCAvIHN1bShjb3VudCkgKiAxMDApICU+JSByb3VuZCgyKSkgJT4lDQogIGZpbHRlcihwZXJjZW50PjQpICU+JQ0KICBhcnJhbmdlKGRlc2MocGVyY2VudCkpIA0KZGF0YS50aGFpLnJpc2sNCmBgYA0KDQpgYGB7cn0NCmRhdGEudGhhaS5yaXNrJHJpc2tbZGF0YS50aGFpLnJpc2skcmlzayA9PSAiQyJdIDwtICJDbG9zZSBjb250YWN0IHdpdGggdGhlIHBhdGllbnQiDQpkYXRhLnRoYWkucmlzayRyaXNrW2RhdGEudGhhaS5yaXNrJHJpc2sgPT0gIkNHdXN0RHIgU2FtdXQgU2FHR0FGIl0gPC0gIkNsdXN0ZXIgU2FtdXQgU2FraG9uIg0KZGF0YS50aGFpLnJpc2skcmlza1tkYXRhLnRoYWkucmlzayRyaXNrID09ICJGIl0gPC0gIlN0YXRlIFF1YXJhbnRpbmUiDQpkYXRhLnRoYWkucmlzayRyaXNrW2RhdGEudGhhaS5yaXNrJHJpc2sgPT0gIkciXSA8LSAiR28gdG8gYSBjcm93ZGVkIHBsYWNlIg0KZGF0YS50aGFpLnJpc2skcmlza1tkYXRhLnRoYWkucmlzayRyaXNrID09ICJBIl0gPC0gIlBlb3BsZSB0cmF2ZWxsaW5nIGZyb20gYWJyb2FkIg0KZGF0YS50aGFpLnJpc2skcmlza1tkYXRhLnRoYWkucmlzayRyaXNrID09ICJVRkdGQXdGIl0gPC0gIlVua25vd24iDQpkYXRhLnRoYWkucmlzayRyaXNrW2RhdGEudGhhaS5yaXNrJHJpc2sgPT0gIkQiXSA8LSAiQ2FyZWVyIGF0IHJpc2siDQpkYXRhLnRoYWkucmlzayRyaXNrW2RhdGEudGhhaS5yaXNrJHJpc2sgPT0gIkNHdXN0RHIgUmF5QUZnIl0gPC0gIkNsdXN0ZXIgUmF5b25nIg0KZGF0YS50aGFpLnJpc2skcmlza1tkYXRhLnRoYWkucmlzayRyaXNrID09ICJDR3VzdERyIFBhdHRheWEgQ2FzQ0ZBIl0gPC0gIkNsdXN0ZXIgUGF0dGF5YSBDYXNpbm8iDQpkYXRhLnRoYWkucmlzayRyaXNrW2RhdGEudGhhaS5yaXNrJHJpc2sgPT0gIkNHdXN0RHIgQUZnIFRHQUZnIl0gPC0gIkNsdXN0ZXIgQW5nIFRob25nIg0KZGF0YS50aGFpLnJpc2sNCmBgYA0KDQpgYGB7cn0NCmRhdGEudGhhaS5yaXNrJHJpc2sgPC0gZmFjdG9yKGRhdGEudGhhaS5yaXNrJHJpc2ssIGxldmVscyA9IGFzLmNoYXJhY3RlcihkYXRhLnRoYWkucmlzayRyaXNrKSkNCmRhdGEudGhhaS5yaXNrJHJpc2sNCmcudGgucmlzayA8LSBkYXRhLnRoYWkucmlzayAlPiUgDQogIGdncGxvdChhZXMoeCA9ICIiLCB5ID0gcGVyY2VudCwgZmlsbCA9IHJpc2spKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuNSkgKw0KICBjb29yZF9wb2xhcigieSIpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgbGFicyh0aXRsZT0nUmlzayBvZiBUaGFpIENvbmZpcm1lZCBDYXNlcyhKYW4gMjAyMCAtIEphbiAyMDIxKScpKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHBlcmNlbnQsICIlIikpLCBjb2xvciA9ICJCbGFjayIsIHNpemUgPSAzLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKw0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVFJVRSkpIA0KZy50aC5yaXNrDQpgYGANCg0KYGBge3J9DQojIENvbmZpcm1lZCBjYXNlcyBkaXZpZGVkIGJ5IGFnZQ0KZGF0YS50aGFpLmFnZSA8LSBkZl90aGFpICU+JQ0KICBncm91cF9ieShhZ2Usc2V4KSAlPiUgDQogIGZpbHRlcihhZ2UgIT0gMCklPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiAgYXJyYW5nZShkZXNjKGNvdW50KSkNCmRhdGEudGhhaS5hZ2UNCmBgYA0KDQpgYGB7cn0NCmRhdGEudGhhaS5hZ2UgPC0gZGF0YS50aGFpLmFnZSMgJT4lIGZpbHRlcihzZXggIT0gIlVua25vd24iKQ0KZ2dwbG90KGRhdGEudGhhaS5hZ2UsYWVzKHg9YWdlLHk9Y291bnQsZmlsbD1zZXgpKStnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikrDQogICAgICBsYWJzKHRpdGxlPSdBZ2Ugb2YgVGhhaSBDb25maXJtZWQgQ2FzZXMgKFN0YWNrKScpK2d1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVCkpDQpgYGANCg0KYGBge3J9DQojIENvbmZpcm1lZCBjYXNlcyBkaXZpZGVkIGJ5IG5hdGlvbmFsaXR5DQpkYXRhLnRoYWkubmF0aW9uYWxpdHkgPC0gZGZfdGhhaQ0KDQpkYXRhLnRoYWkubmF0aW9uYWxpdHkkbmF0aW9uYWxpdHlbZGF0YS50aGFpLm5hdGlvbmFsaXR5JG5hdGlvbmFsaXR5ID09ICI/Pz8/Pz8/PyJdIDwtICJVbmtub3duIg0KZGF0YS50aGFpLm5hdGlvbmFsaXR5JG5hdGlvbmFsaXR5W2RhdGEudGhhaS5uYXRpb25hbGl0eSRuYXRpb25hbGl0eSA9PSAiIl0gPC0gIlVua25vd24iDQpkYXRhLnRoYWkubmF0aW9uYWxpdHkkbmF0aW9uYWxpdHlbZGF0YS50aGFpLm5hdGlvbmFsaXR5JG5hdGlvbmFsaXR5ID09ICJCdXJtYSJdIDwtICJNeWFubWFyIg0KDQpkYXRhLnRoYWkubmF0aW9uYWxpdHkgPC0gZGF0YS50aGFpLm5hdGlvbmFsaXR5ICU+JQ0KICBncm91cF9ieShuYXRpb25hbGl0eSkgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIGZpbHRlcihjb3VudCA+IDExKSU+JQ0KICBhcnJhbmdlKGRlc2MoY291bnQpKQ0KDQpkYXRhLnRoYWkubmF0aW9uYWxpdHkNCmBgYA0KDQpgYGB7cn0NCmRhdGEudGhhaS5uYXRpb25hbGl0eSRjb3VudFtkYXRhLnRoYWkubmF0aW9uYWxpdHkkbmF0aW9uYWxpdHkgPT0gIlVua25vd24iXQ0KZ2dwbG90KGRhdGEudGhhaS5uYXRpb25hbGl0eSwgYWVzKHg9cmVvcmRlcihuYXRpb25hbGl0eSwgY291bnQpLHk9Y291bnQsZmlsbCA9IGNvdW50KSkrIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IixzaG93LmxlZ2VuZCA9IEYpKw0KICAgIGdndGl0bGUoJ05hdGlvbmFsaXR5IG9mIENvbmZpcm1lZCBDYXNlcyBpbiBUaGFpbGFuZCAobG9nIHNjYWxlKScpKw0KICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSsNCiAgICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSkrDQogICAgeGxhYigiIikreWxhYigiTnVtYmVyIG9mIE5hdGlvbmFsaXR5IikrDQogICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9J2xvZzEwJykrY29vcmRfZmxpcCgpK3NjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJibHVlIixoaWdoID0gInJlZCIpDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==
>>>>>>> .merge_file_a10112